Windows 中的 Python 多处理池奇怪行为

שלו*_*סלם 3 python multiprocessing python-3.x

Python 多处理池在 Linux 和 Windows 之间具有不同的行为。

当按工人数量运行方法映射时,在 Linux 中,它在您作为参数提供的特定函数的范围内运行进程,但在 Windows 中,每个工人都在父进程的范围内运行,并再次使用不应该使用的代码.

例如:(烧瓶只是为了使它类似于我的代码)

from multiprocessing import Pool, Event
from flask import Flask

print(">>> This code running for every each worker")

app = Flask(__name__)

terminating = None


def f(**kwargs):
    print("f()")
    x = kwargs.pop("x", 1)
    print(x * x)
    return x * x


def worker_warpper(arg):
    func, kwargs = arg
    return func(**kwargs)


def initializer(terminating_):
    global terminating
    terminating = terminating_


@app.route('/check', methods=['GET'])
def check():
    with Pool(processes=3) as pool:
        ls = [(f, {"x": 2}), (f, {"x": 5}), (f, {"x": 6})]
        pool_map = pool.map(worker_warpper, ls)
    return "Finished"


if __name__ == "__main__":
    print("Listening...")
    app.run(port=5151, host='0.0.0.0')
Run Code Online (Sandbox Code Playgroud)

这段代码应该在 3 个不同的进程中并行运行函数“f”(仅函数“f”)3 次。

但它再次在顶部运行打印。(它并不完全适用于每个进程 - 但是运行“f”的次数与顶部打印再次运行的次数之间存在关系)

print(">>> This code running for every each worker")

仅在 Windows 中,在 Linux 中仅“f”再次运行。

输出:(Linux)

>>> This code running for new worker (not all of the workers)
Listening
...
 * Running on http://0.0.0.0:5151/ (Press CTRL+C to quit)
f()
4
f()
25
f()
36
127.0.0.1 - - 

[29/Jan/2017 11:46:26] "GET /check HTTP/1.1" 200 -
Run Code Online (Sandbox Code Playgroud)

输出:(Windows)

>>> This code running for new worker (not all of the workers)
Listening
...
 * Running on http://0.0.0.0:5151/ (Press CTRL+C to quit)
>>> This code running for new worker (not all of the workers)
f()
4
f()
25
f()
36
127.0.0.1 - - 

[29/Jan/2017 11:46:26] "GET /check HTTP/1.1" 200 -
Run Code Online (Sandbox Code Playgroud)

为什么 linux 和 windows 之间有不同的行为?我能做些什么呢?

如果不清楚,请告诉我,我会以不同的方式尝试。

谢谢!

han*_*ast 6

Windows 和 Linux 之间的区别在于启动子进程的方式。在 Linux 上,子进程使用fork()以下方式启动: 新进程以与父进程相同的状态启动:python 代码已经被解释,并且它获得了父进程内存的副本。

在 Windows 上则完全不同:进程被spawn编辑:一个新的 python 解释器被启动,它再次解析 python 文件并执行它。这就是为什么您print在顶部的流程会再次执行的原因。

有关详细信息,请参阅有关 fork 与 spawn 的文档

一个常见的陷阱是避免if __name__ == '__main__'底部。但是由于您的代码中已经有了它,因此您非常接近“安全代码”。

我该怎么办?

您可以使用Threading代替多处理。当您启动一个新线程时,新线程使用与父线程相同的内存空间。缺点是由于 python 的“全局解释器锁”,您只能使用一个 CPU 内核。

有关详细信息,请参阅此讨论