【问题标题】:Parallel Python for-loop iterating over list of function arguments并行 Python for 循环迭代函数参数列表
【发布时间】:2021-03-25 18:03:28
【问题描述】:

我需要并行化一个 Python for 循环,在该循环中,对于每次迭代,都会调用一个返回两个结果的函数(接受两个参数),然后将这些结果附加到两个不同的列表中。 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 来获得并行。 Python中有没有类似的东西?

我在 Linux 上使用 python 3.8.5,但我需要让它在任何操作系统上运行。

【问题讨论】:

    标签: python list for-loop parallel-processing


    【解决方案1】:

    您可以使用 Python 的 multiprocessing.Pool 功能来实现您的结果。这是来自文档的链接 (https://docs.python.org/3/library/multiprocessing.html#using-a-pool-of-workers) 但是,您将要使用 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 输出实际上是一个元组列表。

    【讨论】:

      【解决方案2】:

      使用concurrent.future 的替代方法,这样您就可以在ProcessPoolExecutor 和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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-03
        • 1970-01-01
        • 2016-09-04
        • 2022-01-18
        • 2012-06-27
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多