2016-01-25 22 views
0

我使用multiprocessing.Pool().imap_unordered(...)並行執行一些任務,並通過計算time.time()在啓動池任務之前和之後的差異來度量其花費的時間。Python 3:'多進程'和'時間'模塊不兼容?

但是,它返回錯誤的結果!當我在程序運行時觀看壁鐘時,它會告訴我大約5秒的運行時間。但程序本身輸出的運行時間僅爲0.1秒。

我也有這種代碼的變種,沒有任何多處理,它需要兩倍的時間,但輸出正確的運行時間。

這裏是我的代碼:

if __name__ == "__main__": 

    n = int(input("How many grids to create? ")) 
    use_multiprocessing = None 
    while use_multiprocessing is None: 
     answer = input("Use multiprocessing to speed things up? (Y/n) ").strip().lower() 
     if len(answer) == 1 and answer in "yn": 
      use_multiprocessing = True if answer == "y" else False 
    t0 = time.time() 

    if use_multiprocessing: 
     processes = cpu_count() 
     worker_pool = Pool(processes) 

     print("Creating {} sudokus using {} processes. Please wait...".format(n, processes)) 
     sudokus = worker_pool.imap_unordered(create_sudoku, range(n), n // processes + 1) 

    else: 
     progress_bar, progress_bar_length = 0, 10 
     sudokus = [] 

     print("Creating {} sudokus".format(n), end="", flush=True) 
     for i in range(n): 
      p = int((i/n) * progress_bar_length) 
      if p > progress_bar: 
       print("." * (p-progress_bar), end="", flush=True) 
       progress_bar = p 
      new_sudoku = create_sudoku() 
      sudokus.append(new_sudoku) 

    t = time.time() - t0 
    l = len(list(sudokus)) 
    print("\nSuccessfully created {} grids in {:.6f}s (average {:.3f}ms per grid)!".format(
     l, t, 1000*t/l 
    )) 

而且這裏的例子來看,這花了約5-6秒的現實(進入網格數後創建和是否使用多,當然):

How many grids to create? 100000 
Use multiprocessing to speed things up? (Y/n) y 
Creating 100000 sudokus using 4 processes. Please wait... 

Successfully created 100000 grids in 0.122141s (average 0.001ms per grid)! 

Process finished with exit code 0 

multiprocessingtime.time()不兼容?我聽說time.clock()可以在這些情況下發生問題,但我認爲time.time()應該是安全的。或者還有其他問題嗎?

回答

2

我想通了。

Pool.imap_unordered(...)返回一個生成器並沒有列表。這意味着,它的元素在方法結束時尚未創建,但只有在我訪問它們時纔會創建。

我在l = len(list(sudokus))這一行中做了這個,在那裏我把生成器轉換成一個列表來獲得長度。在此之前測量完成時間爲一行,因此它正確地報告了初始化發生器所用的時間。這不是我想要的,所以交換這兩條線會導致正確的時間。

我知道我可能不會將生成器轉換爲列表來查找長度然後再次丟棄列表。如果我想要一臺發電機,我必須依靠保存的請求長度,否則我必須使用Pool.map(...),它會生成一個列表並阻塞,直到準備就緒。

相關問題