在 Python (Windows) 中使用池进行多处理
Using pool for multiprocessing in Python (Windows)
我必须以并行方式进行学习才能运行更快。我是 python 中多处理库的新手,还无法成功 运行。
在这里,我正在调查是否每对 (origin, target) 都保留在我研究的不同框架之间的特定位置。几点:
- 这是一个功能,我想运行更快(不是几个进程)。
- 后续处理;这意味着每一帧都与前一帧进行比较。
- 此代码是原始代码的一种非常简单的形式。代码输出 residece_list.
- 我正在使用 Windows OS.
有人可以检查代码(多处理部分)并帮助我改进它以使其工作。谢谢
import numpy as np
from multiprocessing import Pool, freeze_support
def Main_Residence(total_frames, origin_list, target_list):
Previous_List = {}
residence_list = []
for frame in range(total_frames): #Each frame
Current_List = {} #Dict of pair and their residence for frames
for origin in range(origin_list):
for target in range(target_list):
Pair = (origin, target) #Eahc pair
if Pair in Current_List.keys(): #If already considered, continue
continue
else:
if origin == target:
if (Pair in Previous_List.keys()): #If remained from the previous frame, add residence
print "Origin_Target remained: ", Pair
Current_List[Pair] = (Previous_List[Pair] + 1)
else: #If new, add it to the current
Current_List[Pair] = 1
for pair in Previous_List.keys(): #Add those that exited from residence to the list
if pair not in Current_List.keys():
residence_list.append(Previous_List[pair])
Previous_List = Current_List
return residence_list
if __name__ == '__main__':
pool = Pool(processes=5)
Residence_List = pool.apply_async(Main_Residence, args=(20, 50, 50))
print Residence_List.get(timeout=1)
pool.close()
pool.join()
freeze_support()
Residence_List = np.array(Residence_List) * 5
多处理在您此处介绍的上下文中没有意义。
您正在创建五个子进程(以及三个属于池的线程,管理工作人员、任务和结果)来执行 one 函数 once。所有这些都是以系统资源和执行时间为代价的,而您的四个工作进程根本不做任何事情。多处理不会加速函数的执行。您的具体示例中的代码总是比在主进程中直接执行 Main_Residence(20, 50, 50)
慢。
为了使多处理在这种情况下有意义,您手头的工作需要分解为一组可以并行处理的同质任务,它们的结果可能会在以后合并。
举个例子(不一定是好例子),如果你想计算一个数字序列的最大质因数,你可以将计算任何特定数字的那个因数的任务委托给池中的工人.然后几个工作人员将并行进行这些单独的计算:
def largest_prime_factor(n):
p = n
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return p, n
if __name__ == '__main__':
pool = Pool(processes=3)
start = datetime.now()
# this delegates half a million individual tasks to the pool, i.e.
# largest_prime_factor(0), largest_prime_factor(1), ..., largest_prime_factor(499999)
pool.map(largest_prime_factor, range(500000))
pool.close()
pool.join()
print "pool elapsed", datetime.now() - start
start = datetime.now()
# same work just in the main process
[largest_prime_factor(i) for i in range(500000)]
print "single elapsed", datetime.now() - start
输出:
pool elapsed 0:00:04.664000
single elapsed 0:00:08.939000
(largest_prime_factor
函数取自 @Stefan in this answer)
如您所见,池仅比执行相同工作量的单进程执行速度大约快两倍,而 运行 三个进程并行执行。这是由于 multiprocessing/the 池引入的开销。
因此,您声明示例中的代码已被简化。您必须分析您的原始代码,看看它是否可以分解为可以传递到您的池进行处理的同类任务。如果可能的话,使用多处理可能会帮助您加快程序速度。否则,多处理可能会浪费您的时间,而不是节省时间。
编辑:
由于您要求对代码提出建议。我几乎不能说你的功能。你自己说这只是一个提供 MCVE 的简化示例(顺便说一句,非常感谢!大多数人不会花时间将他们的代码精简到最低限度)。无论如何,代码审查请求更适合 Codereview。
尝试一下可用的任务委派方法。在我的质因数示例中,使用 apply_async
会带来 巨大的 惩罚。与使用 map
相比,执行时间增加了九倍。但是我的例子只使用了一个简单的迭代器,你的每个任务需要三个参数。这可能是 starmap
的情况,但仅适用于 Python 3.3。
无论如何,任务数据的 structure/nature 基本上决定了正确的使用方法.
我用 multiprocessing 你的示例函数做了一些 q&d 测试。
输入定义如下:
inp = [(20, 50, 50)] * 5000 # that makes 5000 tasks against your Main_Residence
我 运行 在 Python 3.6 中的三个子流程中,您的功能保持不变,除了删除 print
语句(I/O 是昂贵的)。我使用 starmap
, apply
, starmap_async
and apply_async
并且每次都迭代结果以解决异步结果上的阻塞 get()
。
这是输出:
starmap elapsed 0:01:14.506600
apply elapsed 0:02:11.290600
starmap async elapsed 0:01:27.718800
apply async elapsed 0:01:12.571200
# btw: 5k calls to Main_Residence in the main process looks as bad
# as using apply for delegation
single elapsed 0:02:12.476800
如您所见,尽管所有四种方法所做的工作量相同,但执行时间不同;您选择的 apply_async
似乎是最快的方法。
编码风格。您的代码看起来很...非常规 :) 您使用 Capitalized_Words_With_Underscore 作为您的名称(函数名和变量名),这在 Python 中几乎是禁忌。此外,将名称 Previous_List
分配给字典是......有问题的。查看 PEP 8, especially the section Naming Conventions 以了解 Python.
普遍接受的编码风格
从您的 print
外观来看,您仍在使用 Python 2. 我知道在公司或机构环境中,有时您只能使用它。不过,请记住 clock for Python 2 is ticking
我必须以并行方式进行学习才能运行更快。我是 python 中多处理库的新手,还无法成功 运行。 在这里,我正在调查是否每对 (origin, target) 都保留在我研究的不同框架之间的特定位置。几点:
- 这是一个功能,我想运行更快(不是几个进程)。
- 后续处理;这意味着每一帧都与前一帧进行比较。
- 此代码是原始代码的一种非常简单的形式。代码输出 residece_list.
- 我正在使用 Windows OS.
有人可以检查代码(多处理部分)并帮助我改进它以使其工作。谢谢
import numpy as np
from multiprocessing import Pool, freeze_support
def Main_Residence(total_frames, origin_list, target_list):
Previous_List = {}
residence_list = []
for frame in range(total_frames): #Each frame
Current_List = {} #Dict of pair and their residence for frames
for origin in range(origin_list):
for target in range(target_list):
Pair = (origin, target) #Eahc pair
if Pair in Current_List.keys(): #If already considered, continue
continue
else:
if origin == target:
if (Pair in Previous_List.keys()): #If remained from the previous frame, add residence
print "Origin_Target remained: ", Pair
Current_List[Pair] = (Previous_List[Pair] + 1)
else: #If new, add it to the current
Current_List[Pair] = 1
for pair in Previous_List.keys(): #Add those that exited from residence to the list
if pair not in Current_List.keys():
residence_list.append(Previous_List[pair])
Previous_List = Current_List
return residence_list
if __name__ == '__main__':
pool = Pool(processes=5)
Residence_List = pool.apply_async(Main_Residence, args=(20, 50, 50))
print Residence_List.get(timeout=1)
pool.close()
pool.join()
freeze_support()
Residence_List = np.array(Residence_List) * 5
多处理在您此处介绍的上下文中没有意义。
您正在创建五个子进程(以及三个属于池的线程,管理工作人员、任务和结果)来执行 one 函数 once。所有这些都是以系统资源和执行时间为代价的,而您的四个工作进程根本不做任何事情。多处理不会加速函数的执行。您的具体示例中的代码总是比在主进程中直接执行 Main_Residence(20, 50, 50)
慢。
为了使多处理在这种情况下有意义,您手头的工作需要分解为一组可以并行处理的同质任务,它们的结果可能会在以后合并。
举个例子(不一定是好例子),如果你想计算一个数字序列的最大质因数,你可以将计算任何特定数字的那个因数的任务委托给池中的工人.然后几个工作人员将并行进行这些单独的计算:
def largest_prime_factor(n):
p = n
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return p, n
if __name__ == '__main__':
pool = Pool(processes=3)
start = datetime.now()
# this delegates half a million individual tasks to the pool, i.e.
# largest_prime_factor(0), largest_prime_factor(1), ..., largest_prime_factor(499999)
pool.map(largest_prime_factor, range(500000))
pool.close()
pool.join()
print "pool elapsed", datetime.now() - start
start = datetime.now()
# same work just in the main process
[largest_prime_factor(i) for i in range(500000)]
print "single elapsed", datetime.now() - start
输出:
pool elapsed 0:00:04.664000
single elapsed 0:00:08.939000
(largest_prime_factor
函数取自 @Stefan in this answer)
如您所见,池仅比执行相同工作量的单进程执行速度大约快两倍,而 运行 三个进程并行执行。这是由于 multiprocessing/the 池引入的开销。
因此,您声明示例中的代码已被简化。您必须分析您的原始代码,看看它是否可以分解为可以传递到您的池进行处理的同类任务。如果可能的话,使用多处理可能会帮助您加快程序速度。否则,多处理可能会浪费您的时间,而不是节省时间。
编辑:
由于您要求对代码提出建议。我几乎不能说你的功能。你自己说这只是一个提供 MCVE 的简化示例(顺便说一句,非常感谢!大多数人不会花时间将他们的代码精简到最低限度)。无论如何,代码审查请求更适合 Codereview。
尝试一下可用的任务委派方法。在我的质因数示例中,使用 apply_async
会带来 巨大的 惩罚。与使用 map
相比,执行时间增加了九倍。但是我的例子只使用了一个简单的迭代器,你的每个任务需要三个参数。这可能是 starmap
的情况,但仅适用于 Python 3.3。
无论如何,任务数据的 structure/nature 基本上决定了正确的使用方法.
我用 multiprocessing 你的示例函数做了一些 q&d 测试。
输入定义如下:
inp = [(20, 50, 50)] * 5000 # that makes 5000 tasks against your Main_Residence
我 运行 在 Python 3.6 中的三个子流程中,您的功能保持不变,除了删除 print
语句(I/O 是昂贵的)。我使用 starmap
, apply
, starmap_async
and apply_async
并且每次都迭代结果以解决异步结果上的阻塞 get()
。
这是输出:
starmap elapsed 0:01:14.506600
apply elapsed 0:02:11.290600
starmap async elapsed 0:01:27.718800
apply async elapsed 0:01:12.571200
# btw: 5k calls to Main_Residence in the main process looks as bad
# as using apply for delegation
single elapsed 0:02:12.476800
如您所见,尽管所有四种方法所做的工作量相同,但执行时间不同;您选择的 apply_async
似乎是最快的方法。
编码风格。您的代码看起来很...非常规 :) 您使用 Capitalized_Words_With_Underscore 作为您的名称(函数名和变量名),这在 Python 中几乎是禁忌。此外,将名称 Previous_List
分配给字典是......有问题的。查看 PEP 8, especially the section Naming Conventions 以了解 Python.
从您的 print
外观来看,您仍在使用 Python 2. 我知道在公司或机构环境中,有时您只能使用它。不过,请记住 clock for Python 2 is ticking