连接到远程IPython实例

36
我想在一台机器上运行IPython实例,并从不同的进程(以运行一些Python命令)连接到它(通过局域网)。我知道可以使用zmq实现这一点:http://ipython.org/ipython-doc/dev/development/ipythonzmq.html,但是我找不到关于如何做以及是否已经可行的文档。
任何帮助都将不胜感激!
编辑:
我想能够连接到IPython内核实例并发送Python命令。但是,这不应该通过图形工具(qtconsole)完成,而是要能够从不同的Python脚本中连接到该内核实例...
例如:
external.py
somehow_connect_to_ipython_kernel_instance
instance.run_command("a=6")

相关链接:https://dev59.com/l3XYa4cB1Zd3GeqP631L - user2379410
5个回答

31
如果你想从另一个Python程序中运行内核代码,最简单的方法是连接一个BlockingKernelManager。目前最好的例子是Paul Ivanov的vim-ipython客户端或IPython自己的terminal client
要点如下:
  • ipython内核会写JSON连接文件,位于IPYTHONDIR/profile_<name>/security/kernel-<id>.json,其中包含各种客户端连接和执行代码所需的信息。
  • KernelManagers是用于与内核通信(执行代码、接收结果等)的对象。
一个可工作的示例: 在shell中执行ipython kernel(或者ipython qtconsole,如果你想共享一个已经运行的GUI的内核)。
$> ipython kernel
[IPKernelApp] To connect another client to this kernel, use:
[IPKernelApp] --existing kernel-6759.json

这里写了一个名为'kernel-6759.json'的文件。

然后,您可以运行此Python代码片段连接KernelManager并运行一些代码:

from IPython.lib.kernel import find_connection_file
from IPython.zmq.blockingkernelmanager import BlockingKernelManager

# this is a helper method for turning a fraction of a connection-file name
# into a full path.  If you already know the full path, you can just use that
cf = find_connection_file('6759')

km = BlockingKernelManager(connection_file=cf)
# load connection info and init communication
km.load_connection_file()
km.start_channels()

def run_cell(km, code):
    # now we can run code.  This is done on the shell channel
    shell = km.shell_channel
    print
    print "running:"
    print code

    # execution is immediate and async, returning a UUID
    msg_id = shell.execute(code)
    # get_msg can block for a reply
    reply = shell.get_msg()

    status = reply['content']['status']
    if status == 'ok':
        print 'succeeded!'
    elif status == 'error':
        print 'failed!'
        for line in reply['content']['traceback']:
            print line

run_cell(km, 'a=5')
run_cell(km, 'b=0')
run_cell(km, 'c=a/b')

一次运行的输出:
running:
a=5
succeeded!

running:
b=0
succeeded!

running:
c=a/b
failed!
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
/Users/minrk/<ipython-input-11-fb3f79bd285b> in <module>()
----> 1 c=a/b

ZeroDivisionError: integer division or modulo by zero

查看message spec以获取有关如何解释答复的更多信息。如果相关,则标准输出/错误和显示数据将通过km.iopub_channel传输,并且您可以使用由shell.execute()返回的msg_id将输出与给定执行相关联。

附注:对于这些新功能的文档质量,我深表歉意。我们需要写很多东西。


非常感谢您的出色回答!正是我在寻找的。是否可以接收在内核中运行的命令的输出?例如:"a=2".."print a",然后接收"2"? - Ohad
并且是否可以调用IPython.frontend.terminal.embed.InteractiveShellEmbed()来作为内核打开? - Ohad
输出通过iopub_channel进行。正如我之前提到的,消息规范详细说明了这些消息,vim-ipython和ipython控制台演示了如何处理这些消息。至于嵌入式方面,我认为您正在要求此添加,它应该很快合并。 - minrk
这对我来说在IPython 2.2.0上非常有效,我只需要用IPython.kernel.blocking.client.BlockingKernelClient替换BlockingKernelManager,然后相同的方法调用就可以工作了。谢谢! - talumbau

30
如果您只想进行互动式连接,可以使用SSH转发。我在Stack Overflow上没有找到记录此处的文档,但是这个问题最接近。此答案已在Ipython 0.13上进行了测试。我从这篇博客文章中获得了信息。
  1. Run ipython kernel on the remote machine:

    user@remote:~$ ipython3 kernel
    [IPKernelApp] To connect another client to this kernel, use:
    [IPKernelApp] --existing kernel-25333.json
    
  2. Look at the kernel-25333.json file:

    user@remote:~$ cat ~/.ipython/profile_default/security/kernel-25333.json 
    {
      "stdin_port": 54985, 
      "ip": "127.0.0.1", 
      "hb_port": 50266, 
      "key": "da9c7ae2-02aa-47d4-8e67-e6153eb15366", 
      "shell_port": 50378, 
      "iopub_port": 49981
    }
    
  3. Set up port-forwarding on the local machine:

    user@local:~$ ssh user@remote -f -N -L 54985:127.0.0.1:54985
    user@local:~$ ssh user@remote -f -N -L 50266:127.0.0.1:50266
    user@local:~$ ssh user@remote -f -N -L 50378:127.0.0.1:50378
    user@local:~$ ssh user@remote -f -N -L 49981:127.0.0.1:49981
    
  4. Copy the kernel-25333.json file to the local machine:

    user@local:~$ rsync -av user@remote:.ipython/profile_default/security/kernel-25333.json ~/.ipython/profile_default/security/kernel-25333.json
    
  5. Run ipython on the local machine using the new kernel:

    user@local:~$ ipython3 console --existing kernel-25333.json
    Python 3.2.3 (default, Oct 19 2012, 19:53:16)
    Type "copyright", "credits" or "license" for more information.
    
    IPython 0.13.1.rc2 -- An enhanced Interactive Python.
    ?         -> Introduction and overview of IPython's features.
    %quickref -> Quick reference.
    help      -> Python's own help system.
    object?   -> Details about 'object', use 'object??' for extra details.
    
    
    In [1]: import socket; print(socket.gethostname())
    remote
    

6
如果有人不知道json文件的位置(就像我一样):可以通过运行jupyter --runtime-dir来找到它。 - holastello
正是我在寻找的答案。请注意,可以使用“-f”标志来指定JSON文件的路径。 - Tarik

21

在jupyter分离后,更新minrk的答案。 使用jupyter_client(4.1.1),最简单的代码应该是这样的:

import jupyter_client

cf=jupyter_client.find_connection_file('6759')
km=jupyter_client.BlockingKernelClient(connection_file=cf)
km.load_connection_file()

km.execute('a=5')

请注意:

  • jupyter_client.BlockingKernelClient也可以使用jupyter_client.client.BlockingKernelClient进行别名处理。
  • shell (km.shell_channel)不再具有execute()和get_msg()方法。

目前很难找到更新的文档;在BlockingKernelClient的http://jupyter-client.readthedocs.org/en/latest/上尚未有任何内容。一些代码在https://github.com/jupyter/jupyter_kernel_test中。欢迎任何链接。


1
非常好的答案! - Sung Kim
这真是太棒了!它既极其简单又高效。我喜欢它! - milembar
我正在使用 JupyterLab 笔记本并且两个内核正在运行。此代码仅连接到其中一个内核。我该如何选择它连接的内核?两个内核具有相同的连接文件。 - JulianWgs

5
上面的答案有些过时了。最新版本的ipython解决方案要简单得多,但没有一个地方很好地记录它。所以我想在这里记录一下。
连接到运行在Windows上的ipython内核的解决方案
如果客户端或服务器是linux或其他操作系统,请根据Jupyter下 kernel-1234.json 位于何处?中的相关信息更改kernel-1234.json的位置。
  1. 在您的基于Windows的内核上启动,确保使用pip install ipykernel安装了ipykernel
  2. 使用ipython kernel -f kernel-1234.json启动ipykernel
  3. Windows机器上找到kernel-1234.json文件。该文件可能具有不同的编号,并且很可能位于'C:\Users\me\AppData\Roaming\jupyter\runtime\kernel-1234.json'中:https://stackoverflow.com/a/48332006/4752883
  4. 使用pip install jupyter-consolepip install qtconsole安装Jupyter Console(或Jupyter Qtconsole/notebook):https://jupyter-console.readthedocs.io/en/latest/
  5. 如果您在Windows上,请使用ipconfig查找Windows服务器的IP地址(在Linux上,请在shell提示符下运行ifconfig)。在kernel-1234.json文件中,将IP地址从127.0.0.1更改为服务器的IP地址。如果您是从另一个Windows服务器连接的,则将kernel-1234.json文件复制到本地计算机并记录路径。
  6. 导航到包含kernel-1234.json的文件夹,并使用jupyter console --existing kernel-1234.json启动Jupyter Console

1
在我的Windows安装中,我没有ipykernel,而是有jupyter-kernel。当它启动时,它会显示:Connection file: <path>\kernel-<guid>.json。在这个文件中,它说:“ip”:“127.0.0.1”,所以我不知道如何在客户机上使用此文件并用于尝试使用此内核的其他机器?当我将“127.0.0.1”更改为运行“jupyter-kernel”的机器的IP地址(例如“10.0.0.122”)时,Jupyter控制台会每3秒重复“内核死亡”。 - David Ching
你在服务器和客户端上安装了什么? - alpha_989
1
是的,ping 命令可以正常工作。两台机器都在同一个局域网内(10.0.x.x192.168.x.x 是常见的本地局域网地址)。原始问题明确要求访问局域网上的一台机器上的 IPython。 - David Ching
还有,我在上面的解决方案中打错了一个字,如果你要启动 ipython kernel,你需要使用相同的 kernel-1234.json 文件来启动它。kernel-1234.json 文件应该具有相同的 IP 地址。 - alpha_989
1
谢谢,在服务器上,启动 ipython kernel --ip 10.0.1.122(显式指定其IP地址)会导致它创建的 .json 文件中包含该IP,而不是 127.0.0.1),此外还会导致Windows防火墙提示打开所需的端口。然后,在客户机上,使用相同的 .json 文件启动客户端即可。似乎Python发行版刚开始将IPython客户端部分重命名为Jupyter;我的Anaconda发行版两者都有。当我在客户端上启动 ipython qtconsole 时,它警告我应该开始使用 jupyter qtconsole。非常感谢! - David Ching
显示剩余4条评论

1
如果您正在使用Anaconda,在OS X中JSON文件存储在以下位置:
/Users/[用户名]/Library/Jupyter/runtime/
在Windows中:
c:\Users[用户名]\AppData\Roaming\jupyter\runtime\

1
...以及在Windows上的c:\Users[用户名]\AppData\Roaming\jupyter\runtime\ - 32768
这个回答是否解决了问题?OP想要在一台机器上运行IPython实例,并从不同的进程(通过局域网)连接到它。 - Wai Ha Lee
@WaiHaLee,我认为它提供了解决问题的关键部分。对于初学者来说,“kernel-1234.json”文件的位置可能会令人困惑。有关最新版本的ipython/ipykernel的完整解决方案,请参见:https://dev59.com/8Wkw5IYBdhLWcg3wUI7x#48332182 - alpha_989

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