Python標準庫-concurrent.futures

concurrent.futures模塊提供了一個高層面的接口來實現(xiàn)異步調(diào)用。

concurrent,futures提供了兩種方式來執(zhí)行異步調(diào)用躏救,一種是借助線程,使用ThreadPoolExecutor對象;另一種是借助進程化焕,使用ProcessPoolExecutor對象烛亦,這兩種對象實現(xiàn)了相同的接口,這些接口定義在他們的父類Executor中唧垦。

Executor對象

這是一個抽象類捅儒,提供了異步執(zhí)行的方法。這個類不應(yīng)該被直接使用振亮,應(yīng)該使用上面提到的兩個具體子類巧还。

方法介紹

  • submit(fn, *args, **kwargs)

    執(zhí)行fn(*args, **kwargs)并返回一個Future對象,F(xiàn)uture對象在下面會介紹到坊秸。

with ThreadPoolExecutor(max_workers=1) as executor:
    future = executor.submit(pow, 323, 1235)
    print(future.result())
  • map(func, *iterables, timeout=None, chunksize=1)

    與內(nèi)置的map函數(shù)用法相似麸祷,除了下面兩個區(qū)別:

    1. iterables不是懶加載的
    2. func是異步執(zhí)行的,多個func可以并發(fā)執(zhí)行

    timeout指定一個時間褒搔,如果next()被調(diào)用了且在timeout時間內(nèi)沒有得到結(jié)果則引發(fā)concurrent.futures.TimeoutError阶牍。如果為None,則不限制時間。

    當使用ProcessPoolExecutor時星瘾,設(shè)置chunksize的值可以將iterables分塊走孽,并一次性發(fā)給進程池中的對象,對于很長的迭代對象琳状,使用一個大的chunksize可以提高效率融求。但是對于ThreadPoolExecutor對象,chunksize沒有任何作用算撮。
    我的理解是因為進程之間占用了不同的內(nèi)存空間生宛,所以不同的進程在執(zhí)行時需要先從調(diào)用Executor的進程復(fù)制所需的參數(shù)县昂,當chunksize為1時,每執(zhí)行一次就需要通信一次陷舅,顯然非常浪費時間倒彰,所以設(shè)置一個大點的chunksize可以一次性獲取多次執(zhí)行所需的參數(shù),減少通信的次數(shù)莱睁。而線程因為本來就在同一個內(nèi)存空間中待讳,不存在這個問題,因此沒有影響仰剿。

  • shutdown(wait=True)

    釋放資源的创淡,通過給每個thread或process執(zhí)行join()方法實現(xiàn)。

    通過使用with語句可以避免使用這個方法南吮。

ThreadPoolExecutor(max_workers=None, thread_name_prefix='')

ThreadPoolExecutor是Executor的子類琳彩,通過使用線程池來實現(xiàn)異步調(diào)用。

當一個Future關(guān)聯(lián)的可調(diào)用對象等待另一個Future的結(jié)果時部凑,會發(fā)生死鎖露乏,官方例子如下:

def wait_on_b():
    time.sleep(5)
    print(b.result())  # b will never complete because it is waiting on a.
    return 5
def wait_on_a():
    time.sleep(5)
    print(a.result())  # a will never complete because it is waiting on b.
    return 6
executor = ThreadPoolExecutor(max_workers=2)
a = executor.submit(wait_on_b)
b = executor.submit(wait_on_a)

還有一個:

def wait_on_future():
    f = executor.submit(pow, 5, 2)
    # This will never complete because there is only one worker thread and
    # it is executing this function.
    print(f.result())
executor = ThreadPoolExecutor(max_workers=1)
executor.submit(wait_on_future)

ProcessPoolExecutor(max_workers=None, thread_name_prefix='')

ProcessPoolExecutor同樣也是Executor的子類,通過進程池來實現(xiàn)異步調(diào)用涂邀,且不受全局解釋器鎖的限制瘟仿。

__main__模塊必須被工作子進程導(dǎo)入,這意味這ProcessPoolExecutor不會在交互式解釋器中起作用比勉。

同樣劳较,與線程中提到的一樣,不當?shù)氖褂脮鹚梨i浩聋,具體例子同上观蜗。

ProcessPoolExecutor例子

import concurrent.futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()

可以看出map函數(shù)返回的直接就是結(jié)果,與submit有些區(qū)別赡勘。

Future 對象

Future類封裝了可調(diào)用對象的異步執(zhí)行嫂便,F(xiàn)uture實例由Executor.submit()創(chuàng)建捞镰,不應(yīng)該被直接創(chuàng)建闸与。

方法介紹

  • cancel()

    嘗試取消調(diào)用,如果調(diào)用正在執(zhí)行且無法被取消則返回False岸售,否則調(diào)用會被取消并返回True践樱。

  • cancelled()

    調(diào)用成功被取消時返回True。

  • running()

    如果調(diào)用正在被執(zhí)行且不能被取消則返回True凸丸。

  • done()

    如果調(diào)用成功被取消或者執(zhí)行完成則返回True拷邢。

  • result(timeout=None)

    返回調(diào)用的返回值。

  • add_done_callback(fn)

    這個方法用來添加回調(diào)函數(shù)屎慢,調(diào)用這個方法的future對象會把自己作為唯一參數(shù)傳給函數(shù)fn瞭稼,無論future是執(zhí)行完成還是被取消忽洛,都會調(diào)用fn。

模塊方法

concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)

返回兩個二元組集合环肘,第一個集合名為done欲虚,包含已經(jīng)完成的futures;第二個集合名為not_done,包含沒有完成的futures悔雹。return_when參數(shù)指明了這個方法什么時候返回复哆,一共有三種參數(shù),默認為ALL_COMPLETED.

1. FIRST_COMPLETED:當任何future完成或被取消時返回
2. FIRST_EXCEPTION:當任何future引起一個異常時返回腌零,如果沒有異常梯找,等效于ALL_COMPLETED
3. ALL_COMPLETED:當所有futures完成或被取消時返回

concurrent.futures.as_completed(fs, timeout=None)

返回由fs給出的Future實例迭代器,只有當future完成時才會返回益涧,返回的順序與完成的順序相同锈锤,最先完成的最先返回,如果fs中包含兩個同樣的對象饰躲,只會返回一次牙咏。

官網(wǎng)例子如下:

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

future_to_url是一個字典,一個可迭代對象嘹裂。以submit()返回的future作為鍵妄壶,url作為值。執(zhí)行以后可以發(fā)現(xiàn)輸出的結(jié)果的順序與傳入的url順序不一定是相等的寄狼。

參考連接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丁寄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子泊愧,更是在濱河造成了極大的恐慌伊磺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件删咱,死亡現(xiàn)場離奇詭異屑埋,居然都是意外死亡,警方通過查閱死者的電腦和手機痰滋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門摘能,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人敲街,你說我怎么就攤上這事团搞。” “怎么了多艇?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵逻恐,是天一觀的道長。 經(jīng)常有香客問我,道長复隆,這世上最難降的妖魔是什么拨匆? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮挽拂,結(jié)果婚禮上涮雷,老公的妹妹穿的比我還像新娘。我一直安慰自己轻局,他們只是感情好洪鸭,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仑扑,像睡著了一般览爵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上镇饮,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天蜓竹,我揣著相機與錄音,去河邊找鬼储藐。 笑死俱济,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的钙勃。 我是一名探鬼主播蛛碌,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼辖源!你這毒婦竟也來了蔚携?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤克饶,失蹤者是張志新(化名)和其女友劉穎酝蜒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矾湃,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡亡脑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了邀跃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霉咨。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坞嘀,靈堂內(nèi)的尸體忽然破棺而出躯护,到底是詐尸還是另有隱情惊来,我是刑警寧澤丽涩,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響矢渊,放射性物質(zhì)發(fā)生泄漏继准。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一矮男、第九天 我趴在偏房一處隱蔽的房頂上張望移必。 院中可真熱鬧,春花似錦毡鉴、人聲如沸崔泵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽憎瘸。三九已至,卻和暖如春陈瘦,著一層夾襖步出監(jiān)牢的瞬間幌甘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工痊项, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锅风,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓鞍泉,卻偏偏與公主長得像皱埠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咖驮,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容