高效編程之 concurrent.future


背景

我們知道 Python 中有多線程threading 和多進程multiprocessing 實現並發,

但是這兩個東西開銷很大,一是開啟線程/進程的開銷,二是主程序和子程序之間的通信需要 序列化和反序列化,

所以有些時候需要使用更加高級的用法,然而這些高級用法十分復雜,而且 threading 和 multiprocessing 用法還不一樣。

 

於是誕生了 concurrent.future

1. 它可以解決大部分的復雜問題      【但並不是全部,如果嘗試后效果不好,還需要使用他們的高級用法】

2. 而且統一了線程和進程的用法

 

concurrent.future 提供了 ThreadPoolExecutor 和 ProcessPoolExecutor 兩個類,其實是對 線程池和進程池 的進一步抽象,而且具有以下特點:

3. 主程序可以獲取子程序的狀態和返回值

4. 子程序完成時,主程序能立刻知道

 

效率驗證

求最大公約數,測試數據如下

def gcd(pair):
    # 最大公約數
    a, b = pair
    low = min(a, b)
    for i in range(low, 0, -1):
        if a % i == 0 and b % i == 0:
            return i

numbers = [(1963309, 2265973), (2030677, 3814172), (1551645, 2229620), (2039045, 2020802)]

 

無並發

sum = 0
for i in range(20):
    start = time.time()
    results = list(map(gcd, numbers))
    end = time.time()
    sum += end - start

print(sum/20)           # 0.6637879729270935

 

多線程

from concurrent.futures import ThreadPoolExecutor
sum = 0
for i in range(20):
    start = time.time()
    pool = ThreadPoolExecutor(max_workers=3)
    results = list(pool.map(gcd, numbers))
    end = time.time()
    sum += end - start

print(sum/20)              # 0.9184025406837464

分析:由於全局解釋器鎖GIL的存在,多線程無法利用多核CPU進行並行計算,而是只使用了一個核,加上本身的開銷,計算效率更低了。

通過 資源管理器 查看 CPU 使用率:25%左右    【4核,用了一個】

 

多進程

from concurrent.futures import ProcessPoolExecutor


if __name__ == '__main__':
    sum = 0
    for i in range(20):
        start = time.time()
        pool = ProcessPoolExecutor(max_workers=3)
        results = list(pool.map(gcd, numbers))
        end = time.time()
        sum += end - start

    print(sum/20)               # 0.8655495047569275

分析:利用多核CPU並行計算,比多線程快了點,但是由於本身的開銷,還是沒有無並發效率高,

通過 資源管理器 查看 CPU 使用率:75%左右     【4核,用了三個,max_workers=3】

 

這主要是數據量太小了,體現不出並發的優勢,於是我把數據量稍微加大點

numbers = [(1963309, 2265973), (2030677, 3814172), (1551645, 2229620), (2039045, 2020802)] * 10

重新測試,無並發 7s,多進程 2s,效果明顯提高。

 

注意,在使用多進程時,必須把 多進程代碼 寫在 if __name__ == '__main__' 下面,否則異常,甚至報錯

concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.

 

小結:多線程不適合計算密集型,適合IO密集型,后面我會驗證,多進程適合計算密集型。

 

API 用法

具體方法參照參考資料,非常簡單,這里我就不寫了。

 

 

 

參考資料:

https://www.jianshu.com/p/b9b3d66aa0be


免責聲明!

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



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