多处理比 Windows 中的串行处理慢(但不是在 Linux 中)

Ian*_*rts 7 python parallel-processing multithreading multiprocessing python-multiprocessing

我正在尝试并行化 afor loop以加速我的代码,因为循环处理操作都是独立的。按照在线教程,multiprocessingPython 中的标准库似乎是一个好的开始,我已经将它用于基本示例。

但是,对于我的实际用例,我发现在 Windows 上运行时,并行处理(使用双核机器)实际上要慢一点(<5%)。然而,与串行执行相比,在 Linux 上运行相同的代码会使并行处理速度提高约 25%。

从文档中,我认为这可能与 Window 缺少 fork() 函数有关,这意味着该进程每次都需要重新初始化。但是,我不完全理解这一点,想知道是否有人可以确认这一点?

特别,

--> 这是否意味着调用 python 文件中的所有代码都会为 Windows 上的每个并行进程运行,甚至初始化类和导入包?

--> 如果是这样,是否可以通过将类的副本(例如使用 deepcopy)传递给新进程来避免这种情况?

--> 是否有任何提示/其他策略可以有效地并行化 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()
Run Code Online (Sandbox Code Playgroud)

编辑:我不认为该问题与建议的问题重复,因为这与 Windows 和 Linunx 的差异有关,而在建议的重复问题中根本没有提到这一点。

nox*_*fox 6

NT 操作系统缺少 UNIXfork原语。当一个新进程被创建时,它作为一个空白进程开始。指导新进程如何引导是父进程的责任。

Python multiprocessingAPI 抽象了进程创建,试图为fork,forkserverspawnstart 方法提供相同的感觉。

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

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

上述流程带来的影响很小。

正如您自己注意到的那样,与fork. 这就是为什么您会注意到性能存在如此大的差异。

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

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

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