在for循环中使用Python进行多重处理并传递多个参数

时间:2018-04-11 15:45:11

标签: python multithreading python-3.x python-multiprocessing

我用python脚本做了很多计算。由于它受CPU约束,我使用线程模块的常用方法并没有产生任何性能改进。

我现在正在尝试使用多处理而不是多线程来更好地使用我的CPU并加快冗长的计算。

我在stackoverflow上找到了一些示例代码,但是我没有让脚本接受多个参数。有人可以帮我解决这个问题吗?我之前从未使用过这些模块,我很确定我使用的是Pool.map错误。 - 任何帮助表示赞赏。其他方法也可以实现多处理。

from multiprocessing import Pool

def calculation(foo, bar, foobar, baz):
    # Do a lot of calculations based on the variables
    # Later the result is written to a file.
    result = foo * bar * foobar * baz
    print(result)

if __name__ == '__main__':
    for foo in range(3):
        for bar in range(5):
            for baz in range(4):
                for foobar in range(10):

                    Pool.map(calculation, foo, bar, foobar, baz)
                    Pool.close()
                    Pool.join()

2 个答案:

答案 0 :(得分:3)

正如您所怀疑的那样,您使用map错误的方式多于一种方式。

  • map的要点是在迭代的所有元素上调用一个函数。就像内置map函数一样,但是并行。如果您想要排队一次,只需使用apply_async

  • 针对您特别询问的问题:map采用单参数函数。如果要传递多个参数,可以修改或包装函数以获取单个元组而不是多个参数(我将在最后显示),或者只使用starmap。或者,如果你想使用apply_async,它需要多个参数的函数,但你传递apply_async一个参数元组,而不是单独的参数。

  • 您需要在map个实例上调用Pool,而不是Pool类。您尝试执行的操作类似于从文件类型尝试read而不是从特定的打开文件中读取。
  • 您在每次迭代后尝试关闭并加入Pool。在你完成所有这些操作之前,你不想这样做,或者你的代码只是等待第一个完成,然后为第二个提出例外。

因此,最小的改变是:

if __name__ == '__main__':
    pool = Pool()
    for foo in range(3):
        for bar in range(5):
            for baz in range(4):
                for foobar in range(10):
                    pool.apply_async(calculation, (foo, bar, foobar, baz))
    pool.close()
    pool.join()

请注意,我将所有内容保留在if __name__ == '__main__':块中 - 包括新的Pool()构造函数。我不会在后面的示例中显示这一点,但是对于所有这些都是必要的,原因在文档的Programming guidelines部分中有所解释。 1

如果您想要使用其中一个map函数,则需要一个可迭代的参数,如下所示:

pool = Pool()
args = ((foo, bar, foobar, baz) 
        for foo in range(3) 
        for bar in range(5) 
        for baz in range(4) 
        for foobar in range(10))
pool.starmap(calculation, args)
pool.close()
pool.join()

或者更简单:

pool = Pool()
pool.starmap(calculate, itertools.product(range(3), range(5), range(4), range(10)))
pool.close()
pool.join()

假设您没有使用旧版本的Python,可以使用Pool语句中的with进一步简化它:

with Pool() as pool:
    pool.starmap(calculate, 
                 itertools.product(range(3), range(5), range(4), range(10)))

使用mapstarmap的一个问题是,它确实可以确保按顺序恢复结果。但是你只是回归None并忽略它,为什么这样做呢?

使用apply_async没有问题。

您也可以将map替换为imap_unordered,但没有istarmap_unordered,因此您需要将您的函数包装为不需要starmap:< / p>

def starcalculate(args):
    return calculate(*args)

with Pool() as pool:
    pool.imap_unordered(starcalculate,
                        itertools.product(range(3), range(5), range(4), range(10)))

<子> 1。如果您正在使用spawnforkserver启动方法 - 而spawn是Windows上的默认设置 - 每个子进程都会相当于import您的模块。因此,所有不受__main__后卫保护的顶级代码都会在每个孩子中运行。该模块试图保护您免受这种最严重的后果(例如,代替用计算机爆炸的孩子创建新的孩子,你会经常得到例外),但它不能使代码实际上工作。

答案 1 :(得分:-1)

尝试将calculation作为calculation(foo, bar, foobar, baz)

运行