同时使用iPython笔记本中的多个视图

同时使用iPython笔记本中的多个视图,ipython,ipython-notebook,ipython-parallel,Ipython,Ipython Notebook,Ipython Parallel,我有个问题,希望有人能帮我解决。我试图在iPython笔记本中构建两个不同的平行视图。第一个视图具有ID为0的处理器,第二个视图具有所有其余处理器。我将前缀与每个视图相关联,这样我就可以在不同的处理器上轻松运行不同的东西 我启动了一个后台线程,它使用第二个视图中的处理器进行长时间的计算。当它在后台运行时,我尝试使用第一个视图运行命令,但它不起作用。我收到此错误:ValueError:“”不在列表中 所以,我想知道是否有一种方法可以实现我在这里试图做的事情,或者这是一种不受支持的行为。简而言之,我

我有个问题,希望有人能帮我解决。我试图在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()
#
从IPython导入并行
cli=parallel.Client()
# 
view1=cli[0]
view1.block=True
视图1.激活(“一”)
# 
view2=cli[1:]
view2.block=True
视图2.激活(“两个”)
# 
%px_二次导入时间
def backFunc():
对于范围(10)内的i:
%两次睡眠(5)
%px_两次打印“在bg线程中”
# 
从IPython.lib将后台作业作为bg导入
bgJob=bg.BackgroundJobManager()
bgJob.new('backFunc()'))
# 
%px_一次导入
def foreunc():
对于范围(10)内的i:
%px_一次。睡眠(1)
%px_一次打印“在fg螺纹中”
# 
前脚
foreFunc()一运行,就会出现以下错误:

ValueError: '<IDS|MSG>' is not in list
ValueError:“”不在列表中
有什么想法吗?如果有人有任何想法,我将不胜感激。

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

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

view1 = rc[0]
view2 = rc2[1:]
其余的应该按预期工作

PS:发生什么事了 客户端对象主要是围绕套接字集合的API。每个客户端都有自己的套接字集,并且一个客户端上的所有视图都使用相同的套接字。当您跨线程共享这些套接字时,一个线程可能会收到另一个线程的消息的一部分,从而混淆消息

每条消息实际上是一条由多个部分组成的消息zeromq消息,通过发送或接收,相当于:

multipart = []
for i in range(nparts):
    multipart.append(socket.send/recv())
如果两个线程在同一个套接字上同时执行此操作,则消息可能会交错,因此不需要获取两条消息:

['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']
我们得到

['a1', 'a2', 'b1', 'b2', 'b3'], ['a3']
导致您看到的问题。最简单的修复方法是在不同的线程中使用不同的套接字。另一个解决方案是确保以原子方式接收多部分消息。每个线程分离套接字可以避免锁定的需要,但它确实会根据并发线程的数量成比例地增加需要使用的套接字的数量

PPS…但IPython.parallel是异步的
最后,我会问你为什么要使用后台工作。您不需要使用线程来完成所描述的任务,因为客户端通常不会等待引擎的结果。parallel本质上是异步的,所以您不需要等待作业完成才能提交新作业,也不需要在交互式会话中本地工作。除了调试之外,我一般不建议使用
block=True

谢谢您的详细回答。我这样做的原因是,后台进程的参数可能需要在完成之前进行更改,因此,它不会发送一个可能会占用引擎很长时间的大作业,而是将其分为多个块,并在每个块后检查是否需要更改。但这一切都需要在后台进行,而我用笔记本做其他事情。我使用它进行科学可视化,它本质上是一个预缓存例程,用于可能被查看的帧。我想不出没有线程怎么做。明白了,这很有道理。