1. 程式人生 > >python非同步併發模組concurrent.futures簡析

python非同步併發模組concurrent.futures簡析

本文主要介紹python非同步併發模組.。它非常簡單易用,主要用來實現多執行緒多程序非同步併發

1. 模組安裝

2) python 2.7需要安裝模組,使用命令pip install futures安裝即可

2. Executor物件

class .futures.Executor

Executor是一個抽象類,它提供了非同步執行呼叫的方法。它不能直接使用,但可以通過它的兩個子類ThreadPoolExecutor或者ProcessPoolExecutor進行呼叫。

2.1 Executor.(fn, *args, **kwargs)

fn:需要非同步執行的函式

*args, **kwargs:fn引數

示例:

#-*- coding:utf-8 -*-
from concurrent import futures
 
def test(num):
    import time
    return time.ctime(),num
 
with futures.ThreadPoolExecutor(max_workers=1) as executor:
    future = executor.submit(test,1)
    print future.result()
 
>>>
('Tue Jan 17 15:23:10 2017', 1)


2.2 Executor.

map(func, *iterables, timeout=None)

相當於map(func, *iterables),但是func是非同步執行。timeout的值可以是int或float,如果操作超時,會返回raisesTimeoutError;如果不指定timeout引數,則不設定超時間。

func:需要非同步執行的函式

*iterables:可迭代物件,如列表等。每一次func執行,都會從iterables中取引數。

timeout:設定每次非同步操作的超時時間

示例:

#-*- coding:utf-8 -*-
from concurrent import futures
 
def test(num):
    import time
    return time.ctime(),num
 
data=[1,2,3]
with futures.ThreadPoolExecutor(max_workers=1) as executor:
    for future in executor.map(test,data):
        print future
 
>>>
('Tue Jan 17 15:23:47 2017', 1)
('Tue Jan 17 15:23:47 2017', 2)
('Tue Jan 17 15:23:47 2017', 3)


2.3 Executor.shutdown(wait=True)

釋放系統資源,在Executor.()或 Executor.map()等非同步操作後呼叫。使用with語句可以避免顯式呼叫此方法

3. ThreadPoolExecutor物件

ThreadPoolExecutor類是Executor子類,使用執行緒池執行非同步呼叫.

class concurrent.futures.ThreadPoolExecutor(max_workers)

使用max_workers數目的執行緒池執行非同步呼叫

4. ProcessPoolExecutor物件

ThreadPoolExecutor類是Executor子類,使用程序池執行非同步呼叫.

class concurrent.futures.ProcessPoolExecutor(max_workers=None)

使用max_workers數目的程序池執行非同步呼叫,如果max_workers為None則使用機器的處理器數目(如4核機器max_worker配置為None時,則使用4個程序進行非同步併發)。

示例:

#-*- coding:utf-8 -*-
from concurrent import futures
 
def test(num):
    import time
    return time.ctime(),num
 
def muti_exec(m,n):
    #m 併發次數
    #n 執行次數
 
    with futures.ProcessPoolExecutor(max_workers=m) as executor: #多程序
    #with futures.ThreadPoolExecutor(max_workers=m) as executor: #多執行緒
        executor_dict=dict((executor.submit(test,times), times) for times in range(m*n))
 
    for future in futures.as_completed(executor_dict):
        times = executor_dict[future]
        if future.exception() is not None:
            print('%r generated an exception: %s' % (times,future.exception()))
        else:
            print('RunTimes:%d,Res:%s'% (times, future.result()))
 
if __name__ == '__main__':
    muti_exec(5,1)
 
>>>
RunTimes:0,Res:('Tue Jan 17 15:56:53 2017', 0)
RunTimes:4,Res:('Tue Jan 17 15:56:53 2017', 4)
RunTimes:3,Res:('Tue Jan 17 15:56:53 2017', 3)
RunTimes:1,Res:('Tue Jan 17 15:56:53 2017', 1)
RunTimes:2,Res:('Tue Jan 17 15:56:53 2017', 2)


建議使用多程序併發而不是多執行緒併發,理由如下。

要理解GIL的含義,我們需要從的基礎講起。像C++這樣的語言是編譯型語言,所謂編譯型語言,是指程式輸入到編譯器,編譯器再根據語言的語 法進行解析,然後翻譯成語言獨立的中間表示,最終連結成具有高度優化的機器碼的可執行程式。編譯器之所以可以深層次的對程式碼進行優化,是因為它可以看到整 個程式(或者一大塊獨立的部分)。這使得它可以對不同的語言指令之間的互動進行推理,從而給出更有效的優化手段。

與此相反,是解釋型語言。程式被輸入到直譯器來執行。直譯器在程式執行之前對其並不瞭解;它所知道的只是Python的規則,以及在執行過程 中怎樣去動態的應用這些規則。它也有一些優化,但是這基本上只是另一個級別的優化。由於直譯器沒法很好的對程式進行推導,Python的大部分優化其實是 直譯器自身的優化。

現在我們來看一下問題的癥結所在。要想利用多核系統,Python必須支援多執行緒執行。作為解釋型語言,Python的直譯器必須做到既安全又高效。我們都知道多執行緒程式設計會遇到的問題,直譯器要留意的是避免在不同的執行緒操作內部共享的資料,同時它還要保證在管理使用者執行緒時保證總是有最大化的計算資源。

那麼,不同執行緒同時訪問時,資料的保護機制是怎樣的呢?答案是直譯器全域性鎖。從名字上看能告訴我們很多東西,很顯然,這是一個加在直譯器上的全域性(從直譯器的角度看)鎖(從互斥或者類似角度看)。這種方式當然很安全,但是它有一層隱含的意思(Python初學者需要了解這個):對於任何Python程式,不管有多少的處理器,任何時候都總是隻有一個執行緒在執行。

”為什麼我全新的多執行緒Python程式執行得比其只有一個執行緒的時候還要慢?“許多人在問這個問題時還是非常犯暈的,因為顯然一個具有兩個執行緒的程式要比其只有一個執行緒時要快(假設該程式確實是可並行的)。事實上,這個問題被問得如此頻繁以至於Python的專家們精心製作了一個標準答案:”不要使用多執行緒,請使用多程序”。

所以,對於計算密集型的,我還是建議不要使用python的多執行緒而是使用多程序方式,而對於IO密集型的,還是勸你使用多程序方式,因為使用多執行緒方式出了問題,最後都不知道問題出在了哪裡,這是多麼讓人沮喪的一件事情!

6. 參考文件