文章目錄
一、信號量(瞭解)
同進程的一樣
Semaphore管理一個內置的計數器, 每當調用acquire()時內置計數器-1; 調用release() 時內置計數器+1; 計數器不能小於0;當計數器爲0時,acquire()將阻塞線程直到其他線程調用release()。
實例:(同時只有5個線程可以獲得semaphore,即可以限制最大連接數爲5):
from threading import Thread,Semaphore
import threading
import time
# def func():
# if sm.acquire():
# print (threading.currentThread().getName() + ' get semaphore')
# time.sleep(2)
# sm.release()
def func():
sm.acquire()
print('%s get sm' %threading.current_thread().getName())
time.sleep(3)
sm.release()
if __name__ == '__main__':
sm=Semaphore(5)
for i in range(23):
t=Thread(target=func)
t.start()
二、Event事件(瞭解)
同進程的一樣,看下代碼即可,詳細理論請看多進程的Event事件
from threading import Thread,Event
import threading
import time,random
def conn_mysql():
count=1
while not event.is_set():
if count > 3:
raise TimeoutError('鏈接超時')
print('<%s>第%s次嘗試鏈接' % (threading.current_thread().getName(), count))
event.wait(0.5)
count+=1
print('<%s>鏈接成功' %threading.current_thread().getName())
def check_mysql():
print('\033[45m[%s]正在檢查mysql\033[0m' % threading.current_thread().getName())
time.sleep(random.randint(2,4))
event.set()
if __name__ == '__main__':
event=Event()
conn1=Thread(target=conn_mysql)
conn2=Thread(target=conn_mysql)
check=Thread(target=check_mysql)
conn1.start()
conn2.start()
check.start()
三、定時器
定時器,指定n秒後執行某操作
from threading import Timer
def hello():
print("hello, world")
t = Timer(1, hello)
t.start() # after 1 seconds, "hello, world" will be printed
time.sleep(3)
t.cancel() # 結束定時任務
驗證碼定時器
from threading import Timer
import random,time
class Code:
def __init__(self):
self.make_cache() # 類的對象的初始化階段就已經開始執行定時生成驗證碼任務了
def make_cache(self,interval=5):
self.cache=self.make_code() # 賦值給類的一個屬性,便於類外訪問得到驗證碼
print(self.cache)
self.t=Timer(interval,self.make_cache) # 每隔一段時間,執行一次make_cache函數,同時生成驗證碼的make_code函數也會被重新執行!
self.t.start() # 開始執行
def make_code(self,n=4):
res=''
for i in range(n):
s1=str(random.randint(0,9))
s2=chr(random.randint(65,90))
res+=random.choice([s1,s2])
return res
def check(self):
while True:
inp=input('>>: ').strip()
if inp.upper() == self.cache:
print('驗證成功',end='\n')
self.t.cancel()
break
if __name__ == '__main__':
obj=Code()
obj.check()
四、三種線程安全的隊列
1、queue.Queue(maxsize) 先進先出
'''
import queue
q = queue.Queue() # 先進先出
q.put('1234')
q.put(1234)
q.put(['qweqwe'])
print(q.get())
print(q.get())
print(q.get())
執行結果:
1234
1234
['qweqwe']
'''
2、queue.IifoQueue(maxsize) 堆棧 先進後出
'''
import queue
q = queue.LifoQueue() # 先進後出
q.put('1234')
q.put('123')
q.put(['1234'])
print(q.get())
print(q.get())
print(q.get())
執行結果:
['1234']
123
1234
'''
3、queue.PriorityQueue(maxsize) 優先級隊列,存儲數據時可以設置優先級的隊列,數值越小,優先級越高
'''
import queue
q = queue.PriorityQueue()
q.put((22,'hhhh'))
q.put((12,'wssss'))
q.put((1,'yeeee'))
q.put((44,'seeee'))
print(q.get())
print(q.get())
print(q.get())
print(q.get())
執行結果:
(1, 'yeeee')
(12, 'wssss')
(22, 'alxe')
(44, 'seeee')
'''
五、Python標準模塊–concurrent.futures
1、線程池、進程池介紹
concurrent.futures模塊提供了高度封裝的異步調用接口
ThreadPoolExecutor:線程池,提供異步調用
ProcessPoolExecutor: 進程池,提供異步調用
#2 基本方法
submit(fn, *args, **kwargs) # 異步提交任務
map(func, *iterables, timeout=None, chunksize=1) # 取代for循環submit的操作
shutdown(wait=True) # 相當於進程池的pool.close()+pool.join()操作
wait=True,等待池內所有任務執行完畢回收完資源後才繼續
wait=False,立即返回,並不會等待池內的所有任務執行完畢,當前任務執行完畢就行了
但不管wait參數爲何值,整個程序都會等到所有任務執行完畢
submit和map必須在shutdown之前
# result(timeout=None)
取得結果
# add_done_callback(fn)
異步回調函數
2、線程池創建操作
進程池在多進程那章已經做了詳盡的介紹!因此這裏主要講解線程池。但是線程池和進程池幾乎用法完全一致!
3、map的用法
from concurrent.futures import ThreadPoolExecutor
import os,time,random
def task(n):
print('%s is runing' %os.getpid())
time.sleep(random.randint(1,3))
return n**2
if __name__ == '__main__':
executor=ThreadPoolExecutor(max_workers=3)
# for i in range(11):
# future=executor.submit(task,i)
executor.map(task,range(1,12)) #map取代了for+submit
4、異步回調函數
請見進程池:https://blog.csdn.net/weixin_44571270/article/details/106577032
線程池的異步回調的用法和進程池一樣的!
這裏說一下:我們多線程或進程對一個任務進行處理,用一個變量接收處理完任務的返回值,然後操作數據也可以啊。爲什麼一定要異步回調函數?
用變量接收,那麼原來異步的多線程、多進程,就成了同步了,降低了效率。異步回調函數是任務處理完,函數自己調用異步回調函數處理結果,整個過程還是異步的!而且很方便。