使用 IJava 的 Google Colab 笔记本在安装 + 刷新后卡在“正在连接”

tho*_*ers 5 python java jupyter jupyter-notebook google-colaboratory

在初始 IJava 安装和浏览器页面刷新后,我的所有笔记本都停止连接。

以前做什么工作

  1. 执行第一个单元格
!wget https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip 
!unzip ijava-1.3.0.zip 
!python install.py --sys-prefix
Run Code Online (Sandbox Code Playgroud)
  1. 等待Installed java kernel消息

  2. 刷新浏览器页面。

  3. 使用 Java 代码执行任何单元。

现在发生的是

我可以执行第一个单元格并获取消息Installed java kernel,看到笔记本状态为“已连接”。

但刷新页面后,笔记本的状态永远停留在“正在连接”,

因此没有单元格可以被执行。

--

我免费使用 Google Colab,但由于初始安装仍然有效,并且刷新页面之前笔记本状态为“已连接”,因此这应该不是问题。

知道发生了什么变化,以及如何让我的 Java 笔记本再次连接吗?

--

更新1

页面重新加载后,当我尝试运行包含 Java 代码的单元格时,这是我在一段时间后收到的错误消息:

await connected: disconnected
@https://ssl.gstatic.com/colaboratory-static/common/5f9fa09db4e185842380071022f6c9a6/external_polymer_binary_l10n__en_gb.js:6249:377
promiseReactionJob@[native code]
Run Code Online (Sandbox Code Playgroud)

另外,笔记本设置是

运行时类型:java

硬件加速器:None

这些单元包含非常简单的 Java 代码,没有外部库,没有 CPU 或 GPU 密集型内容。

出于调试目的,我尝试运行其他单元(例如安装 Java 或 Python 代码的单元),但当然,它们在没有连接的情况下也不会执行。

--

更新2

安装 IJava 后和页面重新加载之前,我注意到 Java 内核的路径与“预安装”ir 和 python3 内核的路径不同:

!jupyter kernelspec list

 Available kernels:
  ir         /usr/local/share/jupyter/kernels/ir
  python3    /usr/local/share/jupyter/kernels/python3
  java       /usr/share/jupyter/kernels/java
Run Code Online (Sandbox Code Playgroud)

这可能是问题所在吗?

(我以前从未检查过这一点,所以我不知道最近默认路径是否已更改。)

这是 ipynb 文件的元数据内容:

{
    "nbformat": 4,
    "nbformat_minor": 0,
    "metadata": {
        "colab": {
            "provenance": [{
                "file_id": "...",
                "timestamp": 1670411565504
            }, {
                "file_id": "...",
                "timestamp": 1670311531999
            }, {
                "file_id": "...",
                "timestamp": 1605675807586
            }],
            "authorship_tag": "..."
        },
        "kernelspec": {
            "name": "java",
            "display_name": "java"
        }
    },
    "cells": [{
       ...
    ]}
}
Run Code Online (Sandbox Code Playgroud)

Spe*_*ark 4

在某些时候,colab 将默认传输更改为ipc(从默认tcp),这是 IJava 不支持的。

/usr/bin/python3 /usr/local/bin/jupyter-notebook --ip=... --transport=ipc --port=...

内核启动但从未正确连接,并且不发送 jupyter 正在等待的初始内核信息消息。

当/如果到了某个时刻我们可以要求开始使用tcp传输时,那会更好(请参阅https://github.com/googlecolab/colabtools/issues/3267),但目前我们可以解决这个问题。

解决方法是在 java 内核前面放置一个小的本地代理,该代理连接所有 ipc 通道并将它们转发到另一组连接到 java 内核的 tcp 通道。

第一个单元仍然是通常的安装/设置,但也包括代理的安装:

%%sh
# Install java kernel
wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip 
unzip -q ijava-1.3.0.zip 
python install.py

# Install proxy for the java kernel
wget -qO- https://gist.github.com/SpencerPark/e2732061ad19c1afa4a33a58cb8f18a9/archive/b6cff2bf09b6832344e576ea1e4731f0fb3df10c.tar.gz | tar xvz --strip-components=1
python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py
Run Code Online (Sandbox Code Playgroud)

运行该单元格。你可能有Unrecognized runtime "java"; defaulting to "python3",这没关系。单元运行后输出类似于:

Installed java kernel into "/usr/local/share/jupyter/kernels/java"
e2732061ad19c1afa4a33a58cb8f18a9-b6cff2bf09b6832344e576ea1e4731f0fb3df10c/install_ipc_proxy_kernel.py
e2732061ad19c1afa4a33a58cb8f18a9-b6cff2bf09b6832344e576ea1e4731f0fb3df10c/ipc_proxy_kernel.py
Moving java kernel from /usr/local/share/jupyter/kernels/java...
Wrote modified kernel.json for java_tcp in /usr/local/share/jupyter/kernels/java_tcp/kernel.json
Installing the proxy kernel in place of java in /usr/local/share/jupyter/kernels/java
Installed proxy kernelspec: {"argv": ["/usr/bin/python3", "/usr/local/share/jupyter/kernels/java/ipc_proxy_kernel.py", "{connection_file}", "--kernel=java_tcp"], "env": {}, "display_name": "Java", "language": "java", "interrupt_mode": "message", "metadata": {}}
Proxy kernel installed. Go to 'Runtime > Change runtime type' and select 'java'
install.py:164: DeprecationWarning: replace is ignored. Installing a kernelspec always replaces an existing installation
  install_dest = KernelSpecManager().install_kernel_spec(
Run Code Online (Sandbox Code Playgroud)

请按照打印的说明进行操作:Go to 'Runtime > Change runtime type' and select 'java'. 运行时现在应该显示“Connected to java...”并且您应该能够编写和执行 java 代码。

尝试https://colab.research.google.com/gist/SpencerPark/447de114fcd3e6a272dc140809462e30作为示例基本笔记本。


该设置单元应该是您运行所需的一切,但这里对代理内核中的内容进行了一些解释。它作为要点发布(https://gist.github.com/SpencerPark/e2732061ad19c1afa4a33a58cb8f18a9)。总体思路是:

  1. _tcp使用后缀 ( )重命名真实内核java_tcp,并使用预期名称 ( ) 在其位置安装代理java

  2. 启动代理内核并绑定所有内容,就像代理本身就是内核一样。

    Installed java kernel into "/usr/local/share/jupyter/kernels/java"
    e2732061ad19c1afa4a33a58cb8f18a9-b6cff2bf09b6832344e576ea1e4731f0fb3df10c/install_ipc_proxy_kernel.py
    e2732061ad19c1afa4a33a58cb8f18a9-b6cff2bf09b6832344e576ea1e4731f0fb3df10c/ipc_proxy_kernel.py
    Moving java kernel from /usr/local/share/jupyter/kernels/java...
    Wrote modified kernel.json for java_tcp in /usr/local/share/jupyter/kernels/java_tcp/kernel.json
    Installing the proxy kernel in place of java in /usr/local/share/jupyter/kernels/java
    Installed proxy kernelspec: {"argv": ["/usr/bin/python3", "/usr/local/share/jupyter/kernels/java/ipc_proxy_kernel.py", "{connection_file}", "--kernel=java_tcp"], "env": {}, "display_name": "Java", "language": "java", "interrupt_mode": "message", "metadata": {}}
    Proxy kernel installed. Go to 'Runtime > Change runtime type' and select 'java'
    install.py:164: DeprecationWarning: replace is ignored. Installing a kernelspec always replaces an existing installation
      install_dest = KernelSpecManager().install_kernel_spec(
    
    Run Code Online (Sandbox Code Playgroud)
  3. "tcp"使用支持的参数(传输)和相同的会话信息启动真正的内核。这很重要,因此我们可以将消息直接转发到真正的内核,而无需在中间对它们进行解码。

    shell_socket = create_and_bind_socket(shell_port, zmq.ROUTER)
    stdin_socket = create_and_bind_socket(stdin_port, zmq.ROUTER)
    control_socket = create_and_bind_socket(control_port, zmq.ROUTER)
    iopub_socket = create_and_bind_socket(iopub_port, zmq.PUB)
    hb_socket = create_and_bind_socket(hb_port, zmq.REP)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 为每对通道启动一个 zmq 代理(这就是所有的ProxyKernelClient作用)。

    kernel_manager = KernelManager()
    kernel_manager.kernel_name = args.kernel
    kernel_manager.transport = "tcp"
    kernel_manager.client_factory = ProxyKernelClient
    kernel_manager.autorestart = False
    
    kernel_manager.session.signature_scheme = signature_scheme
    kernel_manager.session.key = key
    
    kernel_manager.start_kernel()
    
    Run Code Online (Sandbox Code Playgroud)
  5. 然后我们就完成了!只需等待托管内核进程退出,然后我们自己也退出。

    Thread(target=zmq.proxy, args=(proxy_server_socket, self.kernel_client_socket)).start()
    
    Run Code Online (Sandbox Code Playgroud)

  • 你是我的英雄!我可以确认这个解决方法非常有效! (3认同)