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 抽象了流程创建,试图为 forkforkserverspawn 启动方法提供相同的感觉。

当您使用 spawn 启动方法时,这就是幕后发生的事情。

  1. 创建了一个空白进程
  2. 空白进程启动一个全新的Python解释器
  3. Python 解释器获得了您通过 Process class 初始化程序
  4. 指定的 MFA(模块函数参数)
  5. Python 解释器加载给定模块解析所有导入
  6. target 函数在模块中查找并使用给定的 argskwargs
  7. 调用

以上流程没有什么意义。

正如您自己注意到的那样,与 fork 相比,这是一项更费力的操作。这就是您注意到性能差异的原因。

随着模块在子进程中从头开始导入,所有导入的副作用都会重新执行。这意味着常量、, 和一级指令将再次执行。

另一方面,在父进程执行期间进行的初始化不会传播到子进程。请参阅 示例。

这就是为什么他们在 multiprocessing 文档中为 Programming Guidelines 中的 Windows 添加了一个特定的段落。我强烈建议阅读编程指南,因为它们已经包含编写可移植多处理代码所需的所有信息。