0

我正在使用這個庫,Tomorrow,它依次使用標準庫中的ThreadPoolExecutor,以允許Async函數調用。爲什麼一個工作者的ThreadPoolExecutor仍然比正常執行更快?

調用@tomorrow.threads(1) 1名工人旋轉了的ThreadPoolExecutor裝飾。

問題

  • 爲什麼更快地執行使用1 thread worker在打電話只是它是(例如正常)的功能?
  • 爲什麼使用10 thread workers代替1,甚至是None執行相同的代碼會更慢?

演示代碼

進口排除

def openSync(path: str): 
    for row in open(path): 
     for _ in row: 
      pass 

@tomorrow.threads(1) 
def openAsync1(path: str): 
    openSync(path) 

@tomorrow.threads(10) 
def openAsync10(path: str): 
    openSync(path) 

def openAll(paths: list): 
    def do(func: callable)->float: 
     t = time.time() 
     [func(p) for p in paths] 
     t = time.time() - t 
     return t 
    print(do(openSync)) 
    print(do(openAsync1)) 
    print(do(openAsync10)) 

openAll(glob.glob("data/*")) 

注:data文件夾中包含18個文件,每個700線隨機文字。

輸出

0工人: 0.0120
1工人: 0.0009
10個工人: 0.0535

我有什麼測試

  • 我已經跑了代碼比夫婦dusin時間多,不同的程序在後臺運行(昨天跑了一堆,今天一對夫婦)。數字改變,ofc,但順序始終相同。 (即,1是最快的,然後是0,然後是10)。
  • 我也嘗試改變執行順序(例如移動do調用)以消除緩存作爲因素,但仍然是一樣的。
    • 原來,以不同的順序按照該次序執行101None結果(1是最快的,然後如圖10所示,然後0)相比每個其他排列。結果表明,不管do調用是否最後執行,都比它先執行或中間執行時慢得多。

結果(從@Dunes接收溶液後)

0工人: 0.0122
1工人: 0。0214
10個工人: 0.0296

+0

對於任何接近準確的性能統計數據的事情,您的樣本量可能太小。在測試諸如文件操作等事情時,您還需要考慮緩存(在操作系統內)的影響。 –

+0

@DarkFalcon我運行的代碼不僅僅是一段時間,不同的程序在後臺運行(昨天跑了一堆,今天跑了一對)。數字改變,ofc,但順序始終相同。 我也嘗試交換執行的順序,例如移動「做」電話。還是一樣。 – Olian04

+1

您的測試顯示不正確。也就是說,在結束測試之前,異步變體不需要等待所有工作完成。也就是說,您只需計算設置所有工作線程需要多長時間,而不需要這些線程完成工作所需的時間。 – Dunes

回答

1

當你調用您的異步功能之一,它返回一個「期貨」對象(的tomorrow.Tomorrow例如在這種情況下)。這使您可以提交所有工作,而無需等待他們完成。但是,從來沒有實際等待工作完成。因此,所有do(openAsync1)確實需要多長時間來設置所有作業(應該非常快)。對於更準確的測試,您需要執行以下操作:

def openAll(paths: list): 
    def do(func: callable)->float: 
     t = time.time() 
     # do all jobs if openSync, else start all jobs if openAsync 
     results = [func(p) for p in paths] 
     # if openAsync, the following waits until all jobs are finished 
     if func is not openSync: 
      for r in results: 
       r._wait() 
     t = time.time() - t 
     return t 
    print(do(openSync)) 
    print(do(openAsync1)) 
    print(do(openAsync10)) 

openAll(glob.glob("data/*")) 

在python中使用其他線程通常會減慢速度。這是因爲全局解釋器鎖定意味着只有一個線程可以處於活動狀態,而不管CPU具有多少個內核。

但是,由於您的工作是IO界限,事情很複雜。更多工作線程可能加快速度。這是因爲單線程可能花更多時間等待硬盤響應,而不是在多線程變體中的各個線程之間的上下文切換之間丟失。

側面說明,即使沒有openAsync1openAsync10等待作業完成,do(openAsync10)可能是慢,因爲它提交一份新的工作,當需要線程之間的多個同步。

+0

謝謝!按預期工作(並學習了一些關於python中的異步的新東西):) – Olian04

相關問題