самый эффективный способ использования multiprocessing
- это разделить работу на n блоков одинакового размера с размером n пула, который должен приблизительно равняться количеству ядер в вашей системе. Причина этого в том, что работа по запуску подпроцессов и связи между ними довольно велика. Если размер работы невелик по сравнению с количеством рабочих фрагментов, тогда издержки IPC становятся значительными.
В вашем случае вы запрашиваете многопроцессорность обрабатывать каждое простое число индивидуально. Лучший способ справиться с этой проблемой - передать каждому работнику диапазон значений (возможно, просто начальное и конечное значение) и вернуть все простые числа в найденном диапазоне.
В случае идентификации простых чисел большого числа выполненная работа увеличивается с начальным значением, и поэтому вы, вероятно, не хотите делить общий диапазон на ровно n кусков, а скорее на n * k равных кусков, с k какое-то разумное, небольшое число, скажем, 10–100. Таким образом, когда некоторые работники заканчивают работу раньше других, остается больше работы, и она может быть эффективно сбалансирована между всеми работниками.
Edit: вот улучшенный пример, чтобы показать, как это решение может выглядеть. Я изменился как можно меньше, чтобы вы могли сравнить яблоки с яблоками.
#!/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()