并行 Python for 循环遍历函数参数列表

Parallel Python for-loop iterating over list of function arguments

我需要并行化一个 Python for 循环,在这个循环中,对于每次迭代,都会调用一个函数(带有两个参数),得到 returns 两个结果,然后是这些结果附加到两个不同的列表。 for 循环遍历两个参数列表。

假设我有以下代码:

def my_f(a, b):
    res1 = a + b
    res2 = a * b
    return res1, res2
    
# lists of arguments
args1 = [1, 2, 3, 4]  
args2 = [5, 6, 7, 8]
    
res_list1, res_list2 = [], []
for i in range(len(args1)):  # loop to parallelize
    res1, res2 = my_f(args1[i], args2[i])
    res_list1.append(res1)
    res_list2.append(res2)

结果应该是

res_list1 = [6, 8, 10, 12]
res_list2 = [5, 12, 21, 32]

我将如何并行实现 运行?

我知道在 C/C++ 中可以只使用 #pragma omp for 来获得平行的 for。 Python有没有类似的东西?

我在 Linux 上使用 python 3.8.5,但我需要让它在任何 OS.

上运行

您可以使用 Python 的 multiprocessing.Pool 功能来实现您的结果。这是文档 (https://docs.python.org/3/library/multiprocessing.html#using-a-pool-of-workers) 中的 link 但是,您将要使用 starmap 而不是使用 map,因为您传递了多个参数。这是我的做法:

from multiprocessing import Pool

def my_f(a, b):
    res1 = a + b
    res2 = a * b
    return res1, res2
   

if __name__ == '__main__':
    args1 = [1, 2, 3, 4]  
    args2 = [5, 6, 7, 8]
        
    
    res = []
    with Pool(processes=4) as pool:
        res = pool.starmap(my_f, zip(args1,args2))

    res_list1 = [r[0] for r in res]
    res_list2 = [r[1] for r in res]

首先,请注意主要代码在 if __name__ == '__main__': 块中。这对 Python 并行性非常重要,因为 Python 实际上会创建新进程而不是线程。 if 块中的任何内容只会被主进程 运行。

其次,我使用 zip 方法将您的两个列表转换为一个可迭代对象。这很重要,因为 starmap 函数必须具有元组形式的参数。

最后,最后几行将 res 列表转换为两个列表,就像您的示例一样。那是因为 res 输出实际上是一个元组列表。

使用 concurrent.future so you can easily switch between ProcessPoolExecutor and ThreadPoolExecutor 的替代方法,以防将来您的工作量发生变化:

from concurrent.futures import ProcessPoolExecutor
  

def worker(args):
    a, b = args
    res1 = a + b
    res2 = a * b

    return res1, res2


def main():
    args1 = [1, 2, 3, 4]
    args2 = [5, 6, 7, 8]

    with ProcessPoolExecutor() as executor:
        result = executor.map(worker, zip(args1, args2))

    a, b = map(list, zip(*result))

    print(a, b)


if __name__ == "__main__":
    main()