2017-02-17 34 views
0

所以我試着在python中進行多處理,並嘗試使用這兩種技術執行一個簡單的map函數並做了基準測試。然而,奇怪的是,它實際上需要更多時間在我創建4個池的代碼中。以下是我的通用代碼:爲什麼給定代碼中的多處理代碼比平常的順序執行需要更多時間?

from datetime import datetime 
from multiprocessing.dummy import Pool as ThreadPool 
def square(x): 
    return x*x 

l = xrange(10000000) 
map(square, l) 

執行此代碼花了大約1.5秒

現在,我創建了4個游泳池,使用下面的代碼多處理:

from datetime import datetime 
from multiprocessing.dummy import Pool as ThreadPool 
def square(x): 
    return x*x 
l = xrange(10000000) 
pool = ThreadPool(4) 
results = pool.map(square, l) 
pool.close() 
pool.join() 

現在,當我爲基準的,多道碼實際上需要更多時間(大約2.5秒)。由於它是一個cpu綁定的任務,我有點困惑,因爲它爲什麼需要更多的時間,實際上應該花費更少的時間。任何意見,我在做什麼錯了?

編輯 - 而不是multiprocessing.dummy我用多處理,它仍然較慢。更慢。

+1

https://wiki.python.org/moin/GlobalInterpreterLock – niemmi

+1

另外,你不是多處理,你是multi_threading_。 '多。dummy'只是線程庫的一個包裝。 https://docs.python.org/2/library/multiprocessing.html#module-multiprocessing.dummy。這就是GIL與此相關的原因。 –

+0

@niemmi嗯,但這是我創建的一個過程,而不是一個線程。糾正我,如果我錯了。 GIL在您創建多個線程時適用。就我所知,多個進程可以在python中使用多個內核。 – Rishabh

回答

1

這並不奇怪。你的測試是一個非常差的測試。您使用線程進行長時間運行的任務。但是你正在測試的是一個幾乎立即返回的函數。這裏主要的因素是設置線程的開銷。這遠遠超過你可能從線程獲得的任何好處。

+0

嗯,是的,你是正確的在這裏設置線程的開銷,這也是我最初的想法。但後來我想在這裏創建多個使用多個CPU核心的進程,因爲我的任務是一個CPU綁定任務。所以這不是一個糟糕的用例,但是你的觀點是正確的。 – Rishabh

0

問題是你正在使用啞元。即多線程,而不是多處理。多線程不會使CPU綁定的任務更快,但只有I/O綁定的任務。

再試一次multiprocessing.Pool,你應該有更多的成功。

multiprocessing.dummy in Python is not utilising 100% cpu

你也需要以某種方式塊你輸入序列到子序列,以做好每一道工序做足夠的計算方法,這是值得的。

我把這個解決方案。看到你只需要在主執行時調用多處理池,問題是Python會啓動執行每個映射的子引擎。

import time 
from multiprocessing import Pool as ThreadPool 

def square(x): 
    return x*x 

def squareChunk(chunk): 
    return [square(x) for x in chunk] 

def chunks(l, n): 
    n = max(1, n) 
    return (l[i:i+n] for i in range(0, len(l), n)) 

def flatten(ll): 
    lst = [] 
    for l in ll: 
     lst.extend(l) 
    return lst 

if __name__ == '__main__': 
    start_time = time.time() 
    r1 = range(10000000) 
    nProcesses = 100 
    chunked = chunks(r1, int(len(r1)/nProcesses)) #split original list in decent sized chunks 
    pool = ThreadPool(4) 
    results = flatten(pool.map(squareChunk, chunked)) 
    pool.close() 
    pool.join() 
    print("--- Parallel map %g seconds ---" % (time.time() - start_time)) 

    start_time = time.time() 
    r2 = range(10000000) 
    squareChunk(r2) 
    print("--- Serial map %g seconds ---" % (time.time() - start_time)) 

我碰到下面的打印輸出:

--- Parallel map 3.71226 seconds --- 
--- Serial map 2.33983 seconds --- 

現在的問題是不應該的並行地圖更快?

這可能是整個組塊會影響我們的效率。但是也可能是當串行處理運行後引擎更「熱身」。於是我轉身測量:

import time 
from multiprocessing import Pool as ThreadPool 

def square(x): 
    return x*x 

def squareChunk(chunk): 
    return [square(x) for x in chunk] 

def chunks(l, n): 
    n = max(1, n) 
    return (l[i:i+n] for i in range(0, len(l), n)) 

def flatten(ll): 
    lst = [] 
    for l in ll: 
     lst.extend(l) 
    return lst 

if __name__ == '__main__': 
    start_time = time.time() 
    r2 = range(10000000) 
    squareChunk(r2) 
    print("--- Serial map %g seconds ---" % (time.time() - start_time)) 

    start_time = time.time() 
    r1 = range(10000000) 
    nProcesses = 100 
    chunked = chunks(r1, int(len(r1)/nProcesses)) #split original list in decent sized chunks 
    pool = ThreadPool(4) 
    results = flatten(pool.map(squareChunk, chunked)) 
    pool.close() 
    pool.join() 
    print("--- Parallel map %g seconds ---" % (time.time() - start_time)) 

現在我得到:

--- Serial map 4.176 seconds --- 
--- Parallel map 2.68242 seconds --- 

所以它不是那麼清楚一方或另一方是否更快。但是如果你想做多處理,你必須考慮創建線程的開銷實際上是否比你期望的更快。你碰到緩存局部性問題等。

+0

請檢查我的編輯。 – Rishabh

+0

我看到您的評論,我也做了一個編輯,因爲您需要爲每個線程解決一個足夠大的問題。計算x * x並不是一個足夠大的問題。 – CodeMonkey

相關問題