IPython并行负载均衡视图的GIL

1 投票
1 回答
733 浏览
提问于 2025-04-18 01:22

我使用Ipython.parallel中的负载均衡视图来对一个可迭代对象调用一个函数,也就是这样:

from IPython.parallel import Client
from functools import partial

rc = Client()
lview = rc.load_balanced_view()
lview.block = True

def func(arg0, arg1, arg2):
    return func2(arg0) + arg1 + arg2

def func2(arg0):
    return 2*arg0

answer = lview.map(partial(func, arg1=A, arg2=B), iterable_data)

那么,func调用func2这件事会不会导致func不能并行执行呢?也就是说,GIL(全局解释器锁)会不会影响到它?我想,当你调用map的时候,每个集群节点都会得到func的一个副本,但它们也会得到func2的副本吗?另外,我使用functools.partial会不会造成什么问题呢?

1 个回答

4

函数调用另一个函数会不会影响并行执行?也就是说,GIL会不会起作用?

完全不会。GIL在这里根本不相关,也不会影响IPython.parallel中的并行执行。GIL只在每个引擎内部协调线程时才会涉及,或者在客户端进程内部。

我假设当你调用map时,每个集群节点会得到func的一个副本,但它们也会得到func2的副本吗?

应该是的,但这实际上会导致你的代码出现问题。IPython并不会自动跟踪闭包和交互命名空间中的代码依赖关系,所以你会看到:

AttributeError: 'DummyMod' object has no attribute 'func'

这是因为partial(func, arg1=A, arg2=B)中包含了对__main__.func的引用,而不是本地func的代码本身。当这个部分到达引擎时,它会被反序列化,并请求__main__.func,但这时是未定义的(__main__是引擎上的交互命名空间)。你可以通过确保funcfunc2在引擎上被定义来解决这个问题:

rc[:].push(dict(func=func, func2=func2))

到那时,你的map应该会按预期工作。

如果你指示IPython使用增强的序列化库dill,那么就能更接近于不需要手动发送引用,但这并不能覆盖所有情况。

撰写回答