上一篇:生產(chǎn)者消費者問題
在之前的文章中我們一般只演示了兩個線程的情況洪唐,在實際中我們要管理多個線程的時候就需要用到線程池。使用線程池管理線程能夠使主線程可以獲得某一線程的狀態(tài)以及返回值,當一個線程完成的時候主線程就能立知道。
這里我們使用的線程池類是ThreadPoolExecutor
识埋,它在concurrent.futures
下。concurrent.futures
中還包括了ProcessPoolExecutor
進程池對象零渐,這個包的設計讓多線程和多進程的接口一致窒舟。
下面是一個例子:
from concurrent.futures import ThreadPoolExecutor
import time
def do_something(name, sec):
print('Start doing %s' % name)
time.sleep(sec)
print('%s completed' % name)
return name
executor = ThreadPoolExecutor(max_workers=2)
task = executor.submit(do_something, 'A', 2)
print(task.done())
print(task.result())
print(task.done())
運行結果:
Start doing A
False
A completed
A
True
首先需要實例化一個線程池對象,ThreadPoolExecutor
類包含一個參數(shù)max_workers
诵盼,表示最大同時運行的線程個數(shù)惠豺。線程池中可以田間任意多個線程银还,但是同時能運行的個數(shù)為max_workers
,其他線程需要等當前正在運行的max_workers
個線程運行完成才能運行洁墙。線程池對象的submit
方法可傳入一個函數(shù)句柄及它的參數(shù)见剩,參數(shù)依次排列。一旦調(diào)用submit
方法扫俺,線程就已經(jīng)開始執(zhí)行或即將執(zhí)行苍苞,并返回一個Future
對象±俏常可調(diào)用Future
對象的done
方法查看線程是否執(zhí)行完成羹呵,該方法非阻塞。還可以調(diào)用result
方法獲得線程的返回值疗琉,該方法阻塞直到線程結束得到返回值冈欢。
如果線程過多,可采用下面的寫法:
from concurrent.futures import ThreadPoolExecutor, as_completed
import random
...
all_task = [executor.submit(do_something, 'task_%d' %i, random.uniform(2,6)) for i in range(10)]
for future in as_completed(all_task):
data = future.result()
print(data)
這里的as_completed
是一個生成器盈简,它會生成已經(jīng)完成的線程的future
對象凑耻。先執(zhí)行完成的線程的future
對象會先被生成,直到所有線程結束柠贤,最后一個線程的future
對象被生成香浩。從結果來看,由于每次的線程切換不同臼勉,執(zhí)行結果也不同邻吭。
另外還可以用ThreadPoolExecutor
對象的map
方法查詢線程是否執(zhí)行完成:
for data in executor.map(do_something, ['task_%d' %i for i in range(10)], [random.uniform(2,6) for i in range(10)]):
print(data)
和之前的as_completed
方法不同,map
生成器是按照參數(shù)的順序返回的宴霸,但是線程執(zhí)行依然是無序的囱晴。而且map
返回的是線程的返回值,不是Future
對象瓢谢。在實踐中最常用的還是第一種方法畸写。
concurrent.futures
還提供了wait
方法,用于阻塞主線程氓扛。其用法是:
from concurrent.futures import wait, ALL_COMPLETED, FIRST_COMPLETED, FIRST_EXCEPTION
wait(fs=all_task, return_when=ALL_COMPLETED)
第一參數(shù)fs
是需要等待的線程列表枯芬,還有一個可選參數(shù)是return_when
,即停止阻塞的條件幢尚,默認是ALL_COMPLETED
破停,即所有線程完成翅楼。除此之外還包括:FIRST_COMPLETED
(第一個線程執(zhí)行完成后)尉剩、FIRST_EXCEPTION
(在子線程中第一次出現(xiàn)拋出錯誤后)。