parallel-processing - python 大迭代号失败

  显示原文与译文双语对照的内容
0 0

我写简单 monte carlo π计算 Python中程序,使用多处理模块。 它也能够正常工作,但是当我传递1E+10迭代每个工作,有些问题发生,并且结果是错误的。 我无法理解什么事,因为1E+9迭代上一切正常 !

import sys
from multiprocessing import Pool
from random import random
def calculate_pi(iters):
    """ Worker function """
    points = 0  # points inside circle
    for i in iters:
        x = random()
        y = random()
        if x ** 2 + y ** 2 <= 1:
            points += 1
    return points
if __name__ == "__main__":
    if len(sys.argv) != 3:
        print "Usage: python pi.py workers_number iterations_per_worker"
        exit()
    procs = int(sys.argv[1])
    iters = float(sys.argv[2])  # 1E+8 is cool
    p = Pool(processes=procs)
    total = iters * procs
    total_in = 0
    for points in p.map(calculate_pi, [xrange(int(iters))] * procs):
        total_in += points
    print "Total: ", total, "In: ", total_in
    print "Pi: ", 4.0 * total_in / total
时间:原作者:6个回答

0 0

多处理的问题似乎有限制最大的int它可以传给子进程在一个x 区域。 下面是一个快速测试:

import sys
from multiprocessing import Pool
def doit(n):
  print n
if __name__ == "__main__":
  procs = int(sys.argv[1])
  iters = int(float(sys.argv[2]))
  p = Pool(processes=procs)
  for points in p.map(doit, [xrange(int(iters))] * procs):
    pass

那么就无须改动:

$ ./multitest.py 2 1E8
xrange(100000000)
xrange(100000000)
$ ./multitest.py 2 1E9
xrange(1000000000)
xrange(1000000000)
$ ./multitest.py 2 1E10
xrange(1410065408)
xrange(1410065408)

这是一部分以更一般问题多处理: 它依赖于标准Python腌制,但有一些细微( 而非证明文件) 扩展传递值。 当生活出现问题,首先要检查的是符合预期到达时的值。

事实上,你可以看到这个问题,玩 pickle,都不碰 multiprocessing( 这并不总是发生,因为这些细微的扩展,但通常是) :

>>> pickle.dumps(xrange(int(1E9)))
'c__builtin__nxrangenp0n(I0nI1000000000nI1ntp1nRp2n.'
>>> pickle.dumps(xrange(int(1E10)))
'c__builtin__nxrangenp0n(I0nI1410065408nI1ntp1nRp2n.'

即使在不了解所有的细节泡菜协议,它应该是显而易见的 I1000000000在第一种情况下是1E9 int形式,而同等的下一个个案是关于1 .41E9块,不1E10,如int 。 你可以试验一下

一个明显的解决方案尝试是传递 int(iters)而不是 xrange(int(iters)),让 calculate_pi创建 xrange从其参数。 ( note: 在某些情况下这样明显的转换可能会影响性能,也许不好。 但在这种情况下,它可能是稍好一点如果anything—a简单对象传递,并且你已并行化 xrangeconstruction—and当然的差异实在太小了,而这可能不重要。 请确定在盲目地转换问题前先思考)

现在和快速测试反映了这种工作方式:

import sys
from multiprocessing import Pool
def doit(n):
  print xrange(n)
if __name__ == "__main__":
    procs = int(sys.argv[1])
    iters = int(float(sys.argv[2]))
    p = Pool(processes=procs)
    for points in p.map(doit, [iters] * procs):
      pass

那么:

$ ./multitest.py 2 1E10
xrange(10000000000)
xrange(10000000000)

不过,你仍然遇到较大的限制:

$ ./multitest.py 2 1E100
OverflowError: Python int too large to convert to C long

同样,它有同样的基本问题。 解决这个问题的一种方法是将arg传递一路向下为字符串,并且做int( float( ) ) 内的子进程。

作为说明: 我这么做的原因 iters = int(float(sys.argv[2]))而不是像现在这样 iters = float(sys.argv[2]),然后使用 int(iters)以后是避免意外使用float iters值再( 成OP是版本的确实,计算 total因此, total_in / total) 。

并请记住,如果得到足够大数字,你遇到的边界C double类型: 1E23通常99999999999999991611392,不是100000000000000000000000 。

原作者:
...