2011-08-26 81 views
8

所以我最近幾天一直在使用python的多處理庫,我真的很喜歡處理池。這很容易實現,我可以看到很多用途。我已經完成了我之前聽說過的幾個項目,以熟悉它,並且最近完成了一個蠻力強制hang子手遊戲的程序。python prime crunching:處理池速度較慢?

Anywho,我做的所有100萬至200單螺紋,並通過處理池之間萬元素數相加的執行時間compairison。現在,對於劊子手排排坐,投入處理池改善執行時間的遊戲了約8倍(i7處理器與8個核),但磨出來的這些素數的時候,它實際上由4

幾乎因素增加處理時間

誰能告訴我這是爲什麼?這裏是有興趣的人看或測試它的代碼:

#!/user/bin/python.exe 
import math 
from multiprocessing import Pool 

global primes 
primes = [] 

def log(result): 
    global primes 

    if result: 
     primes.append(result[1]) 

def isPrime(n): 
    if n < 2: 
     return False 
    if n == 2: 
     return True, n 

    max = int(math.ceil(math.sqrt(n))) 
    i = 2 
    while i <= max: 
     if n % i == 0: 
      return False 
     i += 1 
    return True, n 


def main(): 

    global primes 

    #pool = Pool() 

    for i in range(1000000, 2000000): 
     #pool.apply_async(isPrime,(i,), callback = log) 
     temp = isPrime(i) 
     log(temp) 

    #pool.close() 
    #pool.join() 

    print sum(primes) 

    return 

if __name__ == "__main__": 
    main() 

它會目前在單個線程中運行,經過處理池運行,取消游泳池語句和註釋掉的其他行主循環。

+0

實際上,將你的代碼加速到很多地獄的東西是刪除全局部分。如果你有本地變量,查找速度會快得多。 –

+0

無法刪除全局變量而無需添加類,因爲我只能將一個變量傳遞給回調函數。 – Laharah

+0

相關:[最快的方式列出蟒蛇中N以下的所有素數](http://stackoverflow.com/q/2068372/4279) – jfs

回答

14

使用multiprocessing最有效的方法是將工作分成n個相等大小的塊,其中n是池的大小,應該大約爲系統上的核心數。原因在於啓動子進程和它們之間的通信的工作量非常大。如果工作量與工作塊的數量相比較小,那麼IPC的開銷就會變得很大。

在你的情況,你問多單獨處理每一個素。處理這個問題的一個更好的方法是向每個工作者傳遞一系列值(可能只是一個開始和結束值),並讓它返回找到的該範圍內的所有素數。

在識別大質數的情況下,所做的工作會隨着起始值增長,因此您可能不希望將總範圍劃分爲n個塊,而是將n * k個相等的塊與k一些合理的數字,例如10 - 100。這樣,當一些工作人員在別人之前完成時,還有更多工作要做,並且可以在所有工人之間有效平衡。

編輯:下面是一個改進的示例,顯示該解決方案的外觀。我儘可能少地改變了,所以你可以比較蘋果和蘋果。

#!/user/bin/python.exe 
import math 
from multiprocessing import Pool 

global primes 
primes = set() 

def log(result): 
    global primes 

    if result: 
     # since the result is a batch of primes, we have to use 
     # update instead of add (or for a list, extend instead of append) 
     primes.update(result) 

def isPrime(n): 
    if n < 2: 
     return False 
    if n == 2: 
     return True, n 

    max = int(math.ceil(math.sqrt(n))) 
    i = 2 
    while i <= max: 
     if n % i == 0: 
      return False 
     i += 1 
    return True, n 

def isPrimeWorker(start, stop): 
    """ 
    find a batch of primes 
    """ 
    primes = set() 
    for i in xrange(start, stop): 
     if isPrime(i): 
      primes.add(i) 

    return primes 



def main(): 

    global primes 

    pool = Pool() 

    # pick an arbitrary chunk size, this will give us 100 different 
    # chunks, but another value might be optimal 
    step = 10000 

    # use xrange instead of range, we don't actually need a list, just 
    # the values in that range. 
    for i in xrange(1000000, 2000000, step): 
     # call the *worker* function with start and stop values. 
     pool.apply_async(isPrimeWorker,(i, i+step,), callback = log) 

    pool.close() 
    pool.join() 

    print sum(primes) 

    return 

if __name__ == "__main__": 
    main() 
+0

非常感謝,這個答案正是我所期待的。我知道啓動過程需要很多開銷,但並不是說爲他們增加新工作也是如此昂貴。 – Laharah