Python多进程工作池中初始化的使用

6
我正在研究使用multiprocessing.Pool来创建worker,尝试初始化worker的一些状态。该池可以采用可调用的方式进行初始化,但它没有传递对已初始化worker的引用。我看到的少数示例都使用全局变量,这似乎非常不好。
有没有好的方法可以使用multiprocessing.Pool来初始化worker状态?
编辑:一个例子:
我有一些worker,每个worker都会进行一些相对昂贵的初始化(绑定到socket),我不想每次都要做这些初始化。我可以手动初始化我的sockets,然后在分配工作时将它们传递给worker,但是在进程之间共享文件描述符很复杂,甚至不可能。所以每次我想处理请求时都必须进行初始化和绑定。

1
我有点不清楚为什么你的初始化函数需要一个对工作线程的引用,也许你可以提供一个稍微具体但最小化的示例来说明你想要做什么。 - mgilson
你知道无法确定某个函数调用将被分配给哪个工作线程吗?那么为什么不在函数参数中包含该状态呢? - Sven Marnach
1个回答

7

从技术上讲,正确的做法是将初始化函数的结果作为参数传递给工作进程执行的每个函数。

在这种情况下,拥有全局变量是安全的,因为它们是私有对象,生存在不同进程的单独域中。

我的一般建议是使用合理的 可重入 编程风格构建函数,并利用 multiprocessing 功能允许全局变量。

保留您的示例,以下send 函数需要一些上下文(在本例中为 socket):

def send(socket, data):
    pass # ... your code here
    return dust

初始化代码和工作线程执行的基础代码都会依赖全局变量以方便操作。
socket = None
def init(address, port):
    global socket
    socket = magic(address, port)

def job(data):
    global socket
    assert socket is not None
    return send(socket, data)

pool = multithreading.Pool(N, init, [address, port])
pool.map(job, ['foo', 'bar', 'baz'])

通过这种编码方式,测试变得简单自然,无需使用多进程。你可以将全局状态视为完全安全的上下文胶囊。
作为方便的附加点,请记住,multiprocessing 不擅长发送复杂数据(例如回调)。最好的方法是发送简单的数据片段(字符串、列表、字典、collections.namedtuple ...),并在工作进程侧重构复杂的数据结构(使用初始化函数)。

这对我来说是一个重大的启发,谢谢!我现在正在使用这个模式来实现pypdfium2的并行渲染器。 - mara004

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接