Windows 中的多处理比串行处理慢(但 Linux 中不是)
Multiprocessing slower than serial processing in Windows (but not in Linux)
我正在尝试并行化一个 for loop
来加速我的代码,因为循环处理操作都是独立的。按照在线教程,Python 中的标准 multiprocessing
库似乎是一个良好的开端,我已经将其用于基本示例。
然而,对于我的实际用例,我发现并行处理(使用双核机器)实际上比 Windows 上的 运行 慢一点(<5%)。 运行 Linux 上的相同代码,与串行执行相比,并行处理速度提高了约 25%。
根据文档,我认为这可能与 Window 缺少 fork() 函数有关,这意味着每次都需要重新初始化进程。但是,我并不完全理解这一点,不知道是否有人可以证实这一点?
特别是
--> 这是否意味着调用 python 文件中的所有代码都为 Windows 上的每个并行进程获取 运行,甚至初始化 classes 和导入包裹?
--> 如果是这样,是否可以通过某种方式将 class 的副本(例如使用深度复制)传递到新进程中来避免这种情况?
--> 是否有针对 unix 和 windows.
代码设计的有效并行化的任何技巧/其他策略
我的确切代码很长并且使用了很多文件,所以我创建了一个伪代码样式的示例结构,希望能说明问题。
# Imports
from my_package import MyClass
imports many other packages / functions
# Initialization (instantiate class and call slow functions that get it ready for processing)
my_class = Class()
my_class.set_up(input1=1, input2=2)
# Define main processing function to be used in loop
def calculation(_input_data):
# Perform some functions on _input_data
......
# Call method of instantiate class to act on data
return my_class.class_func(_input_data)
input_data = np.linspace(0, 1, 50)
output_data = np.zeros_like(input_data)
# For Loop (SERIAL implementation)
for i, x in enumerate(input_data):
output_data[i] = calculation(x)
# PARALLEL implementation (this doesn't work well!)
with multiprocessing.Pool(processes=4) as pool:
results = pool.map_async(calculation, input_data)
results.wait()
output_data = results.get()
编辑:我不认为这个问题与所建议的问题重复,因为这与 Windows 和 Linunx 的差异有关,而在建议的重复问题中根本没有提到这一点。
NT 操作系统缺少 UNIX fork
原语。创建新进程时,它以空白进程开始。家长有责任指导新流程如何 bootstrap.
Python multiprocessing
API 抽象了流程创建,试图为 fork
、forkserver
和 spawn
启动方法提供相同的感觉。
当您使用 spawn
启动方法时,这就是幕后发生的事情。
- 创建了一个空白进程
- 空白进程启动一个全新的Python解释器
- Python 解释器获得了您通过
Process
class 初始化程序 指定的 MFA(模块函数参数)
- Python 解释器加载给定模块解析所有导入
target
函数在模块中查找并使用给定的 args
和 kwargs
调用
以上流程没有什么意义。
正如您自己注意到的那样,与 fork
相比,这是一项更费力的操作。这就是您注意到性能差异的原因。
随着模块在子进程中从头开始导入,所有导入的副作用都会重新执行。这意味着常量、, 和一级指令将再次执行。
另一方面,在父进程执行期间进行的初始化不会传播到子进程。请参阅 示例。
这就是为什么他们在 multiprocessing
文档中为 Programming Guidelines 中的 Windows 添加了一个特定的段落。我强烈建议阅读编程指南,因为它们已经包含编写可移植多处理代码所需的所有信息。
我正在尝试并行化一个 for loop
来加速我的代码,因为循环处理操作都是独立的。按照在线教程,Python 中的标准 multiprocessing
库似乎是一个良好的开端,我已经将其用于基本示例。
然而,对于我的实际用例,我发现并行处理(使用双核机器)实际上比 Windows 上的 运行 慢一点(<5%)。 运行 Linux 上的相同代码,与串行执行相比,并行处理速度提高了约 25%。
根据文档,我认为这可能与 Window 缺少 fork() 函数有关,这意味着每次都需要重新初始化进程。但是,我并不完全理解这一点,不知道是否有人可以证实这一点?
特别是
--> 这是否意味着调用 python 文件中的所有代码都为 Windows 上的每个并行进程获取 运行,甚至初始化 classes 和导入包裹?
--> 如果是这样,是否可以通过某种方式将 class 的副本(例如使用深度复制)传递到新进程中来避免这种情况?
--> 是否有针对 unix 和 windows.
代码设计的有效并行化的任何技巧/其他策略我的确切代码很长并且使用了很多文件,所以我创建了一个伪代码样式的示例结构,希望能说明问题。
# Imports
from my_package import MyClass
imports many other packages / functions
# Initialization (instantiate class and call slow functions that get it ready for processing)
my_class = Class()
my_class.set_up(input1=1, input2=2)
# Define main processing function to be used in loop
def calculation(_input_data):
# Perform some functions on _input_data
......
# Call method of instantiate class to act on data
return my_class.class_func(_input_data)
input_data = np.linspace(0, 1, 50)
output_data = np.zeros_like(input_data)
# For Loop (SERIAL implementation)
for i, x in enumerate(input_data):
output_data[i] = calculation(x)
# PARALLEL implementation (this doesn't work well!)
with multiprocessing.Pool(processes=4) as pool:
results = pool.map_async(calculation, input_data)
results.wait()
output_data = results.get()
编辑:我不认为这个问题与所建议的问题重复,因为这与 Windows 和 Linunx 的差异有关,而在建议的重复问题中根本没有提到这一点。
NT 操作系统缺少 UNIX fork
原语。创建新进程时,它以空白进程开始。家长有责任指导新流程如何 bootstrap.
Python multiprocessing
API 抽象了流程创建,试图为 fork
、forkserver
和 spawn
启动方法提供相同的感觉。
当您使用 spawn
启动方法时,这就是幕后发生的事情。
- 创建了一个空白进程
- 空白进程启动一个全新的Python解释器
- Python 解释器获得了您通过
Process
class 初始化程序 指定的 MFA(模块函数参数)
- Python 解释器加载给定模块解析所有导入
target
函数在模块中查找并使用给定的args
和kwargs
调用
以上流程没有什么意义。
正如您自己注意到的那样,与 fork
相比,这是一项更费力的操作。这就是您注意到性能差异的原因。
随着模块在子进程中从头开始导入,所有导入的副作用都会重新执行。这意味着常量、
另一方面,在父进程执行期间进行的初始化不会传播到子进程。请参阅
这就是为什么他们在 multiprocessing
文档中为 Programming Guidelines 中的 Windows 添加了一个特定的段落。我强烈建议阅读编程指南,因为它们已经包含编写可移植多处理代码所需的所有信息。