-->

Python的大迭代数失败(Python large iterations number fail)

2019-07-31 21:19发布

我写了简单的蒙特卡洛π计算的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

Answer 1:

这个问题似乎是多有限制,最大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__\nxrange\np0\n(I0\nI1000000000\nI1\ntp1\nRp2\n.'
>>> pickle.dumps(xrange(int(1E10)))
'c__builtin__\nxrange\np0\n(I0\nI1410065408\nI1\ntp1\nRp2\n.'

即使没有学习咸菜协议的所有细节,它应该是显而易见的是, I1000000000在第一种情况是1E9为int,而接下来的情况下相当于块是约1.41E9,不是1E10,作为一个int。 你可以尝试

一个显而易见的解决办法是尝试通过int(iters)代替xrange(int(iters))并让calculate_pi创建xrange从它的参数。 (注:在某些情况下,这样一个明显的转变会损害性能,也许不好,但在这种情况下,它可能如果有的话,一个简单的对象传递稍微好一点,和你并行的。 xrange建设和课程的差异是如此的渺小,它可能并不重要。只要确保盲目地转化三思。)

而一个快速测试表明,这种现在工作:

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(浮动(A))的子过程中。

作为一个方面说明:原因我做iters = int(float(sys.argv[2]))而不是仅仅iters = float(sys.argv[2])然后使用int(iters)后面是为了避免偶然使用浮子iters以后值(作为OP的版本确实,在计算total和因此total_in / total )。

而且要记住,如果你得到足够大的数字,你运行到C double类型的限制: 1E23通常99999999999999991611392,不100000000000000000000000。



文章来源: Python large iterations number fail