python異步並發模塊concurrent.futures入門詳解


concurrent.futures模塊詳解

Executor對象

class concurrent.futures.Executor

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

我們可以將相應的tasks直接放入線程池/進程池,不需要維護Queue來操心死鎖的問題,線程池/進程池會自動幫我們調度。

Future可以把它理解為一個在未來完成的操作,這是異步編程的基礎,傳統編程模式下比如我們操作queue.get的時候,在等待返回結果之前會產生阻塞,cpu不能讓出來做其他事情,而Future的引入幫助我們在等待的這段時間可以完成其他的操作

2.1.1 Executor.submit(fn, *args, **kwargs)

submit(fn,*args,**kwargs) 異步提交任務

fn:需要異步執行的函數

*args, **kwargs:fn參數

使用submit函數來提交線程需要執行的任務(函數名和參數)到線程池中,並返回該任務的句柄(類似於文件、畫圖),注意submit()不是阻塞的,而是立即返回。

通過submit函數返回的任務句柄,能夠使用done()方法判斷該任務是否結束。

使用cancel()方法可以取消提交的任務,如果任務已經在線程池中運行了,就取消不了。

 

2.1.2 Executor.map(func, *iterables, timeout=None)

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

func:需要異步執行的函數

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

timeout:設置每次異步操作的超時時間

 

2.1.3 Executor.shutdown(wait=True)

釋放系統資源,在Executor.submit()或 Executor.map()等異步操作后調用。使用with語句可以避免顯式調用此方法

shutdown(wait=True) 相當於進程池的pool.close()+pool.join()操作
wait=True,等待池內所有任務執行完畢回收完資源后才繼續,--------》默認
wait=False,立即返回,並不會等待池內的任務執行完畢
但不管wait參數為何值,整個程序都會等到所有任務執行完畢
submit和map必須在shutdown之前

 

2.3 ThreadPoolExecutor對象

ThreadPoolExecutor類是Executor子類,使用線程池執行異步調用.

class concurrent.futures.ThreadPoolExecutor(max_workers)

使用max_workers數目的線程池執行異步調用

executor = ThreadPoolExecutor(concurrent_size)

 

2.4 ProcessPoolExecutor對象

ThreadPoolExecutor類是Executor子類,使用進程池執行異步調用.

class concurrent.futures.ProcessPoolExecutor(max_workers=None)

使用max_workers數目的進程池執行異步調用,如果max_workers為None則使用機器的處理器數目(如4核機器max_worker配置為None時,則使用4個進程進行異步並發)。

executor = ProcessPoolExecutor(concurrent_size)
ProcessPoolExecutor(n):n表示池里面存放多少個進程,之后的連接最大就是n的值


as_completed

as_completed()方法是一個生成器,在沒有任務完成的時候,會阻塞,在有某個任務完成的時候,會yield這個任務,就能執行for循環下面的語句,然后繼續阻塞住,循環到所有的任務結束。從結果也可以看出,先完成的任務會先通知主線程。

參數是任務(submit的返回值)列表

 

wait

wait方法可以讓主線程阻塞,直到滿足設定的要求。

wait方法接收3個參數,等待的任務序列、超時時間以及等待條件。等待條件return_when默認為ALL_COMPLETED,表明要等待所有的任務都結束。等待條件還可以設置為FIRST_COMPLETED,表示第一個任務完成就停止等待。



 

要想利用多核系統,Python必須支持多線程運行。作為解釋型語言,Python的解釋器必須做到既安全又高效。我們都知道多線程編程會遇到的問題,解釋器要留意的是避免在不同的線程操作內部共享的數據,同時它還要保證在管理用戶線程時保證總是有最大化的計算資源。

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

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

 

Python 多線程安全

進程是資源分布的單元

線程是進程中真正執行代碼的

進程運行起來,會有一個主線程進行運行 

父子線程:相互獨立運行,當所有的子線程執行完后,主線程才執行完

 

多進程中,每個進程中所有數據(包括全局變量)都各有擁有一份,互不影響

在一個進程內的所有線程共享全局變量,能夠在不適用其他方式的前提下完成多線程之間的數據共享(但是局部變量是自己的)

 

字典,列表當做參數傳遞給線程,會當做全局變量

使用 copy.deepcopy(x) 來實現對象的深拷貝來實現值傳遞

 

#創建鎖
mutex = threading.Lock()
#鎖定
mutex.acquire([blocking])
#釋放
mutex.release()

鎖的好處:

  • 確保了某段關鍵代碼只能由一個線程從頭到尾完整地執行

鎖的壞處:

  • 阻止了多線程並發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了
  • 由於可以存在多個鎖,不同的線程持有不同的鎖,並試圖獲取對方持有的鎖時,可能會造成死鎖(死鎖可以通過銀行家算法解決)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM