我很难理解如何使用Python的多处理模块。
我有一个从 1
到 n
的总和,其中 n=10^10
,它太大而无法放入列表,这似乎是许多使用多处理的在线示例的主旨。
有没有办法将范围"拆分"为一定大小的段,然后对每个段执行总和?
例如
def sum_nums(low,high):
result = 0
for i in range(low,high+1):
result += i
return result
我想通过将sum_nums(1,10**10)
分解为许多sum_nums(1,1000) + sum_nums(1001,2000) + sum_nums(2001,3000)...
来计算等等。我知道有一个紧密形式的n(n+1)/2
但假装我们不知道。
这是我尝试过的
import multiprocessing
def sum_nums(low,high):
result = 0
for i in range(low,high+1):
result += i
return result
if __name__ == "__main__":
n = 1000
procs = 2
sizeSegment = n/procs
jobs = []
for i in range(0, procs):
process = multiprocessing.Process(target=sum_nums, args=(i*sizeSegment+1, (i+1)*sizeSegment))
jobs.append(process)
for j in jobs:
j.start()
for j in jobs:
j.join()
#where is the result?
我找到了多进程的用法。池和 map() 更简单
使用您的代码:
from multiprocessing import Pool
def sum_nums(args):
low = int(args[0])
high = int(args[1])
return sum(range(low,high+1))
if __name__ == "__main__":
n = 1000
procs = 2
sizeSegment = n/procs
# Create size segments list
jobs = []
for i in range(0, procs):
jobs.append((i*sizeSegment+1, (i+1)*sizeSegment))
pool = Pool(procs).map(sum_nums, jobs)
result = sum(pool)
>>> print result
>>> 500500
您可以在完全没有multiprocessing
的情况下完成此总和,并且仅使用生成器可能更简单,如果不是更快的话。
# prepare a generator of generators each at 1000 point intervals
>>> xr = (xrange(1000*i+1,i*1000+1001) for i in xrange(10000000))
>>> list(xr)[:3]
[xrange(1, 1001), xrange(1001, 2001), xrange(2001, 3001)]
# sum, using two map functions
>>> xr = (xrange(1000*i+1,i*1000+1001) for i in xrange(10000000))
>>> sum(map(sum, map(lambda x:x, xr)))
50000000005000000000L
但是,如果你想使用 multiprocessing
,您也可以这样做。 我正在使用一个multiprocessing
分支,它更擅长序列化(但除此之外,并没有真正的不同)。
>>> xr = (xrange(1000*i+1,i*1000+1001) for i in xrange(10000000))
>>> import pathos
>>> mmap = pathos.multiprocessing.ProcessingPool().map
>>> tmap = pathos.multiprocessing.ThreadingPool().map
>>> sum(tmap(sum, mmap(lambda x:x, xr)))
50000000005000000000L
没有multiprocessing
的版本更快,在我的笔记本电脑上大约需要一分钟。 multiprocessing
版本需要几分钟,因为生成多个 python 进程的开销很大。
如果您有兴趣,请在此处pathos
:https://github.com/uqfoundation
首先,解决内存问题的最佳方法是使用迭代器/生成器而不是列表:
def sum_nums(low, high):
result = 0
for i in xrange(low, high+1):
result += 1
return result
在 python3 中,range() 生成一个迭代器,所以这在 python2 中才需要
。现在,多处理的用武之地是当您想要将处理拆分为不同的进程或 CPU 内核时。 如果您不需要控制单个工作线程,最简单的方法是使用进程池。 这将允许您将函数映射到池并获取输出。 您也可以使用 apply_async
一次将作业应用于池,并获得延迟结果
.get()
获得: import multiprocessing
from multiprocessing import Pool
from time import time
def sum_nums(low, high):
result = 0
for i in xrange(low, high+1):
result += i
return result
# map requires a function to handle a single argument
def sn((low,high)):
return sum_nums(low, high)
if __name__ == '__main__':
#t = time()
# takes forever
#print sum_nums(1,10**10)
#print '{} s'.format(time() -t)
p = Pool(4)
n = int(1e8)
r = range(0,10**10+1,n)
results = []
# using apply_async
t = time()
for arg in zip([x+1 for x in r],r[1:]):
results.append(p.apply_async(sum_nums, arg))
# wait for results
print sum(res.get() for res in results)
print '{} s'.format(time() -t)
# using process pool
t = time()
print sum(p.map(sn, zip([x+1 for x in r], r[1:])))
print '{} s'.format(time() -t)
在我的机器上,仅使用 10**10 调用sum_nums
需要将近 9 分钟,但使用 Pool(8)
和 n=int(1e8)
将其减少到一分钟多一点。