1. 使用內(nèi)置模塊
在使用多線程處理任務(wù)時(shí)也不是線程越多越好,由于在切換線程的時(shí)候,需要切換上下文環(huán)境,依然會造成cpu的大量開銷。為解決這個(gè)問題,線程池的概念被提出來了。預(yù)先創(chuàng)建好一個(gè)合理數(shù)量的線程池,讓過來的任務(wù)立刻能夠使用,就形成了線程池。
在Python3中,創(chuàng)建線程池是通過concurrent.futures函數(shù)庫中的ThreadPoolExecutor類來實(shí)現(xiàn)的。
import time
import threading
from concurrent.futures import ThreadPoolExecutor
def target():
for i in range(5):
print('running thread-{}:{}'.format(threading.get_ident(), i))
time.sleep(1)
# 創(chuàng)建一個(gè)最大容納數(shù)量為5的線程池
pool = ThreadPoolExecutor(5)
for i in range(10):
# 往線程池上塞任務(wù)
pool.submit(target)
創(chuàng)建線程池還可以使用更優(yōu)雅的方式,就是使用上下文管理器
with ThreadPoolExecutor(5) as pool:
for i in range(100):
pool.submit(target)
直接運(yùn)行代碼,從輸出可以看出,前面我們設(shè)置線程池最大線程數(shù),會保證“同時(shí)”僅有五個(gè)線程在工作。
running thread-123145483767808:0
running thread-123145489022976:0
running thread-123145494278144:0
running thread-123145499533312:0
running thread-123145504788480:0
running thread-123145483767808:1
running thread-123145489022976:1
running thread-123145499533312:1
running thread-123145494278144:1
running thread-123145504788480:1
running thread-123145489022976:2
running thread-123145499533312:2
running thread-123145483767808:2
running thread-123145504788480:2
running thread-123145494278144:2
....
示例完畢,來說明一下:
使用 with 語句 ,通過 ThreadPoolExecutor 構(gòu)造實(shí)例,同時(shí)傳入 max_workers 參數(shù)來設(shè)置線程池中最多能同時(shí)運(yùn)行的線程數(shù)目。
使用 submit 函數(shù)來提交線程需要執(zhí)行的任務(wù)到線程池中,并返回該任務(wù)的句柄(類似于文件、畫圖),注意 submit() 不是阻塞的,而是立即返回。
通過使用 done() 方法判斷該任務(wù)是否結(jié)束。上面的例子可以看出,提交任務(wù)后立即判斷任務(wù)狀態(tài),顯示四個(gè)任務(wù)都未完成。在延時(shí)2.5后,task1 和 task2 執(zhí)行完畢,task3 仍在執(zhí)行中。
使用 result() 方法可以獲取任務(wù)的返回值。
2. 自定義線程池
除了使用上述第三方模塊的方法之外,我們還可以自己結(jié)合前面所學(xué)的消息隊(duì)列來自定義線程池。
這里我們就使用queue來實(shí)現(xiàn)一個(gè)上面同樣效果的例子,大家感受一下。
import time
import threading
from queue import Queue
def target(queue):
while True:
task = queue.get()
if task == "stop":
queue.task_done()
break
task()
queue.task_done()
def do_task():
for i in range(5):
print('running thread-{}:{}'.format(threading.get_ident(), i))
time.sleep(1)
class MyQueue(Queue):
def close(self):
for i in range(self.maxsize):
self.put("stop")
def custome_pool(task_func, max_workers):
queue = MyQueue(max_workers)
for n in range(max_workers):
t = threading.Thread(target=task_func, args=(queue,))
t.daemon = True
t.start()
return queue
pool = custome_pool(task_func=target, max_workers=5)
for i in range(10):
pool.put(do_task)
pool.close()
pool.join()
輸出是和上面是完全一樣的效果
running thread-123145469886464:0
running thread-123145475141632:0
running thread-123145485651968:0
running thread-123145490907136:0
running thread-123145480396800:0
running thread-123145469886464:1
running thread-123145480396800:1
running thread-123145475141632:1
running thread-123145490907136:1
running thread-123145485651968:1
...
構(gòu)建線程池的方法,是可以很靈活的,大家有空可以自己多研究。但是建議只要掌握一種自己熟悉的,能快速上手的就好了。
審核編輯:湯梓紅
-
模塊
+關(guān)注
關(guān)注
7文章
2845瀏覽量
53405 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4419瀏覽量
67737 -
python
+關(guān)注
關(guān)注
58文章
4880瀏覽量
90241
發(fā)布評論請先 登錄
使用PYTHON進(jìn)行的跨平臺仿真
生產(chǎn)環(huán)境數(shù)據(jù)庫連接池耗盡的全流程排查與性能優(yōu)化實(shí)戰(zhàn)
Linux多線程對比單線程的優(yōu)勢
用PLC實(shí)現(xiàn)卷徑計(jì)算的兩種算法
有多少種方法可以進(jìn)行頻響曲線測量?
python創(chuàng)建線程池的兩種方法
評論