1. 使用內(nèi)置模塊
在使用多線程處理任務(wù)時(shí)也不是線程越多越好,由于在切換線程的時(shí)候,需要切換上下文環(huán)境,依然會(huì)造成cpu的大量開(kāi)銷(xiāo)。為解決這個(gè)問(wèn)題,線程池的概念被提出來(lái)了。預(yù)先創(chuàng)建好一個(gè)合理數(shù)量的線程池,讓過(guò)來(lái)的任務(wù)立刻能夠使用,就形成了線程池。
在Python3中,創(chuàng)建線程池是通過(guò)concurrent.futures函數(shù)庫(kù)中的ThreadPoolExecutor類(lèi)來(lái)實(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)行代碼,從輸出可以看出,前面我們?cè)O(shè)置線程池最大線程數(shù),會(huì)保證“同時(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
....
示例完畢,來(lái)說(shuō)明一下:
使用 with 語(yǔ)句 ,通過(guò) ThreadPoolExecutor 構(gòu)造實(shí)例,同時(shí)傳入 max_workers 參數(shù)來(lái)設(shè)置線程池中最多能同時(shí)運(yùn)行的線程數(shù)目。
使用 submit 函數(shù)來(lái)提交線程需要執(zhí)行的任務(wù)到線程池中,并返回該任務(wù)的句柄(類(lèi)似于文件、畫(huà)圖),注意 submit() 不是阻塞的,而是立即返回。
通過(guò)使用 done() 方法判斷該任務(wù)是否結(jié)束。上面的例子可以看出,提交任務(wù)后立即判斷任務(wù)狀態(tài),顯示四個(gè)任務(wù)都未完成。在延時(shí)2.5后,task1 和 task2 執(zhí)行完畢,task3 仍在執(zhí)行中。
使用 result() 方法可以獲取任務(wù)的返回值。
2. 自定義線程池
除了使用上述第三方模塊的方法之外,我們還可以自己結(jié)合前面所學(xué)的消息隊(duì)列來(lái)自定義線程池。
這里我們就使用queue來(lái)實(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文章
2837瀏覽量
53283 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4417瀏覽量
67501 -
python
+關(guān)注
關(guān)注
57文章
4876瀏覽量
90025
發(fā)布評(píng)論請(qǐng)先 登錄
Linux多線程對(duì)比單線程的優(yōu)勢(shì)
用PLC實(shí)現(xiàn)卷徑計(jì)算的兩種算法
有多少種方法可以進(jìn)行頻響曲線測(cè)量?
python創(chuàng)建線程池的兩種方法
評(píng)論