并行 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()
我需要并行化一个 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()