在Firefox的IPython Notebook中是否有等效于CTRL + C的功能来中断正在运行的单元格?

问题:在Firefox的IPython Notebook中是否有等效于CTRL + C的功能来中断正在运行的单元格?

我已经开始使用IPython Notebook并很喜欢它。有时,我编写需要占用大量内存或存在无限循环的错误代码。我发现“中断内核”选项缓慢或不可靠,有时我不得不重新启动内核,从而丢失了内存中的所有内容。

有时我还会编写一些脚本,导致O​​S X内存不足,并且必须进行硬重启。我肯定不是100%,但如果我写这样的错误报告之前,并在终端运行的Python,我平时可以CTRL+ C我的脚本。

我在Mac OS X上使用IPython Notebook的Anaconda发行版和Firefox。

I’ve started to use the IPython Notebook and am enjoying it. Sometimes, I write buggy code that takes massive memory requirements or has an infinite loop. I find the “interrupt kernel” option sluggish or unreliable, and sometimes I have to restart the kernel, losing everything in memory.

I also sometimes write scripts that cause OS X to run out of memory, and I have to do a hard reboot. I’m not 100% sure, but when I’ve written bugs like this before and ran Python in the terminal, I can usually CTRL+C my scripts.

I am using the Anaconda distribution of IPython notebook with Firefox on Mac OS X.


回答 0

我可能是错的,但我敢肯定的是,“中断内核”按钮,只需发送一个SIGINT信号到代码,您当前运行(这种想法是费尔南多的评论支持在这里,这是相同的东西,击打) CTRL + C可以。python中的某些进程比其他进程更突然地处理SIGINT。

如果您迫切需要停止iPython Notebook中正在运行的内容,并从终端启动iPython Notebook,则可以在该终端中按两次CTRL + C来中断整个iPython Notebook服务器。这将完全停止iPython Notebook,这意味着将无法重新启动或保存您的工作,因此,这显然不是一个很好的解决方案(您需要按CTRL + C两次,因为这是一项安全功能,因此人们无需意外地做)。但是,在紧急情况下,它通常比“中断内核”按钮更快地终止进程。

I could be wrong, but I’m pretty sure that the “interrupt kernel” button just sends a SIGINT signal to the code that you’re currently running (this idea is supported by Fernando’s comment here), which is the same thing that hitting CTRL+C would do. Some processes within python handle SIGINTs more abruptly than others.

If you desperately need to stop something that is running in iPython Notebook and you started iPython Notebook from a terminal, you can hit CTRL+C twice in that terminal to interrupt the entire iPython Notebook server. This will stop iPython Notebook alltogether, which means it won’t be possible to restart or save your work, so this is obviously not a great solution (you need to hit CTRL+C twice because it’s a safety feature so that people don’t do it by accident). In case of emergency, however, it generally kills the process more quickly than the “interrupt kernel” button.


回答 1

您可以按I两次以中断内核。

仅当您处于命令模式时,这才有效。如果尚未启用,请按Esc启用它。

You can press I twice to interrupt the kernel.

This only works if you’re in Command mode. If not already enabled, press Esc to enable it.


回答 2

是IPython Notebook的快捷方式。

Ctrl-m i中断内核。(即后面的唯一字母i Ctrl-m

根据这个答案,I两次也可以。

Here are shortcuts for the IPython Notebook.

Ctrl-m i interrupts the kernel. (that is, the sole letter i after Ctrl-m)

According to this answer, I twice works as well.


回答 3

添加到上面的内容:如果中断不起作用,则可以重新启动内核。

转到内核下拉菜单>>重新启动>>重新启动并清除输出。这通常可以解决问题。如果仍然无法解决问题,请在终端(或任务管理器)中终止内核,然后重新启动。

中断不适用于所有进程。使用R内核时,我尤其遇到这个问题。

To add to the above: If interrupt is not working, you can restart the kernel.

Go to the kernel dropdown >> restart >> restart and clear output. This usually does the trick. If this still doesn’t work, kill the kernel in the terminal (or task manager) and then restart.

Interrupt doesn’t work well for all processes. I especially have this problem using the R kernel.


回答 4

更新:将我的解决方案变成了独立的python脚本。

此解决方案为我节省了不止一次。希望其他人觉得它有用。该python脚本将查找使用不止cpu_thresholdCPU的jupyter内核,并提示用户将a发送SIGINT给内核(KeyboardInterrupt)。它将一直发送,SIGINT直到内核的cpu使用率低于为止cpu_threshold。如果存在多个行为异常的内核,它将提示用户中断每个内核(按CPU使用率从高到低的顺序排列)。非常感谢gcbeltramini编写了使用jupyter api查找jupyter内核名称的代码。该脚本已经在python3的MACOS上进行了测试,并且需要jupyter笔记本,请求,json和psutil。

将脚本放在您的主目录中,然后用法如下所示:

python ~/interrupt_bad_kernels.py
Interrupt kernel chews cpu.ipynb; PID: 57588; CPU: 2.3%? (y/n) y

下面的脚本代码:

from os import getpid, kill
from time import sleep
import re
import signal

from notebook.notebookapp import list_running_servers
from requests import get
from requests.compat import urljoin
import ipykernel
import json
import psutil


def get_active_kernels(cpu_threshold):
    """Get a list of active jupyter kernels."""
    active_kernels = []
    pids = psutil.pids()
    my_pid = getpid()

    for pid in pids:
        if pid == my_pid:
            continue
        try:
            p = psutil.Process(pid)
            cmd = p.cmdline()
            for arg in cmd:
                if arg.count('ipykernel'):
                    cpu = p.cpu_percent(interval=0.1)
                    if cpu > cpu_threshold:
                        active_kernels.append((cpu, pid, cmd))
        except psutil.AccessDenied:
            continue
    return active_kernels


def interrupt_bad_notebooks(cpu_threshold=0.2):
    """Interrupt active jupyter kernels. Prompts the user for each kernel."""

    active_kernels = sorted(get_active_kernels(cpu_threshold), reverse=True)

    servers = list_running_servers()
    for ss in servers:
        response = get(urljoin(ss['url'].replace('localhost', '127.0.0.1'), 'api/sessions'),
                       params={'token': ss.get('token', '')})
        for nn in json.loads(response.text):
            for kernel in active_kernels:
                for arg in kernel[-1]:
                    if arg.count(nn['kernel']['id']):
                        pid = kernel[1]
                        cpu = kernel[0]
                        interrupt = input(
                            'Interrupt kernel {}; PID: {}; CPU: {}%? (y/n) '.format(nn['notebook']['path'], pid, cpu))
                        if interrupt.lower() == 'y':
                            p = psutil.Process(pid)
                            while p.cpu_percent(interval=0.1) > cpu_threshold:
                                kill(pid, signal.SIGINT)
                                sleep(0.5)

if __name__ == '__main__':
    interrupt_bad_notebooks()

UPDATE: Turned my solution into a stand-alone python script.

This solution has saved me more than once. Hopefully others find it useful. This python script will find any jupyter kernel using more than cpu_threshold CPU and prompts the user to send a SIGINT to the kernel (KeyboardInterrupt). It will keep sending SIGINT until the kernel’s cpu usage goes below cpu_threshold. If there are multiple misbehaving kernels it will prompt the user to interrupt each of them (ordered by highest CPU usage to lowest). A big thanks goes to gcbeltramini for writing code to find the name of a jupyter kernel using the jupyter api. This script was tested on MACOS with python3 and requires jupyter notebook, requests, json and psutil.

Put the script in your home directory and then usage looks like:

python ~/interrupt_bad_kernels.py
Interrupt kernel chews cpu.ipynb; PID: 57588; CPU: 2.3%? (y/n) y

Script code below:

from os import getpid, kill
from time import sleep
import re
import signal

from notebook.notebookapp import list_running_servers
from requests import get
from requests.compat import urljoin
import ipykernel
import json
import psutil


def get_active_kernels(cpu_threshold):
    """Get a list of active jupyter kernels."""
    active_kernels = []
    pids = psutil.pids()
    my_pid = getpid()

    for pid in pids:
        if pid == my_pid:
            continue
        try:
            p = psutil.Process(pid)
            cmd = p.cmdline()
            for arg in cmd:
                if arg.count('ipykernel'):
                    cpu = p.cpu_percent(interval=0.1)
                    if cpu > cpu_threshold:
                        active_kernels.append((cpu, pid, cmd))
        except psutil.AccessDenied:
            continue
    return active_kernels


def interrupt_bad_notebooks(cpu_threshold=0.2):
    """Interrupt active jupyter kernels. Prompts the user for each kernel."""

    active_kernels = sorted(get_active_kernels(cpu_threshold), reverse=True)

    servers = list_running_servers()
    for ss in servers:
        response = get(urljoin(ss['url'].replace('localhost', '127.0.0.1'), 'api/sessions'),
                       params={'token': ss.get('token', '')})
        for nn in json.loads(response.text):
            for kernel in active_kernels:
                for arg in kernel[-1]:
                    if arg.count(nn['kernel']['id']):
                        pid = kernel[1]
                        cpu = kernel[0]
                        interrupt = input(
                            'Interrupt kernel {}; PID: {}; CPU: {}%? (y/n) '.format(nn['notebook']['path'], pid, cpu))
                        if interrupt.lower() == 'y':
                            p = psutil.Process(pid)
                            while p.cpu_percent(interval=0.1) > cpu_threshold:
                                kill(pid, signal.SIGINT)
                                sleep(0.5)

if __name__ == '__main__':
    interrupt_bad_notebooks()