同时在iPython Notebook中使用多个视图

时间:2014-11-30 16:05:53

标签: ipython ipython-notebook ipython-parallel

我有一个问题,我希望有人能帮助我弄明白。我正在尝试在iPython笔记本中构建两个不同的并行视图。第一个视图的处理器ID为0,第二个视图具有所有其余处理器。我将前缀与每个视图相关联,这样我就可以在不同的处理器上轻松运行不同的东西。

我启动了一个后台线程,它使用第二个视图中的处理器进行长时间的计算。当它在后台运行时,我尝试使用第一个视图运行命令,但它不起作用。我收到此错误:ValueError:''不在列表中。

所以我想知道是否有办法做我想在这里做的事,或者这是不支持的行为。简而言之,我想使用不同的处理器创建两个不同的视图。视图之间不会共享处理器。然后我希望能够运行使用一个视图的后台任务,同时使用另一个视图进行无关的任务。

这是一个导致错误的小示例脚本。我不确定如何直接发布笔记本,所以我只是复制并粘贴了由它生成的python脚本。

# <codecell>

from IPython import parallel
cli = parallel.Client()

# <codecell>

view1 = cli[0]
view1.block = True
view1.activate("_one")

# <codecell>

view2 = cli[1:]
view2.block = True
view2.activate("_two")

# <codecell>

%px_two import time
def backFunc():
    for i in range(10):
        %px_two time.sleep(5)
        %px_two print "In bg thread"

# <codecell>

from IPython.lib import backgroundjobs as bg
bgJob = bg.BackgroundJobManager()
bgJob.new('backFunc()')

# <codecell>

%px_one import time
def foreFunc():
    for i in range(10):
        %px_one time.sleep(1)
        %px_one print "In fg thread"


# <codecell>

foreFunc()

运行foreFunc()后,会出现错误:

ValueError: '<IDS|MSG>' is not in list

有什么想法?我很感激任何人的想法。

1 个答案:

答案 0 :(得分:1)

简答

客户端使用的套接字不是线程安全的,因此您不能在多个线程中同时使用它们。您可以同时使用集群,但是您需要为后台任务创建一个单独的客户端,后者将拥有自己的一组套接字:

rc = parallel.Client()
rc2 = parallel.Client()

view1 = rc[0]
view2 = rc2[1:]

其余的应该按预期工作。

PS:发生了什么

Client对象主要是围绕一组套接字的API。每个客户端都有自己的套接字,一个客户端上的所有视图都使用相同的套接字。当您跨线程共享这些套接字时,一个线程可能会获取一个用于另一个线程的消息的一部分,从而使该消息无效。

每条消息实际上是一条多部分消息zeromq消息,与zmq.Socket.send/recv_multipart一起发送或接收,相当于:

multipart = []
for i in range(nparts):
    multipart.append(socket.send/recv())

如果两个线程在同一个套接字上同时执行此操作,则消息可能会交错,因此不会收到两条消息:

['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']

我们得到了

['a1', 'a2', 'b1', 'b2', 'b3'], ['a3']

导致您遇到的问题。最简单的解决方法是在不同的线程中使用不同的套接字。另一种解决方法是使用locking来确保以原子方式接收多部分消息。每个线程分离套接字允许您避免锁定的需要,但它确实增加了您需要与并发线程数成比例使用的套接字数量。

PPS ......但IPython.parallel是异步

我将完全问你为什么要使用后台工作。您不需要使用线程来完成您描述的任务,因为客户端通常不会等待引擎的结果。 IPython.parallel本质上是异步的,因此您不需要等待作业完成以提交新作业,或者在交互式会话中本地工作。我通常不建议将block=True用于除调试之外的任何其他内容。