如果你使用过Jupyter笔记本,你就使用过一个内核。内核是一个执行来自前端进程的代码的进程。通常,如果你在Python中工作,你使用的内核是IPython内核。IPython内核通常与Python版本相匹配,并包含与运行Jupyter笔记本进程相同的库。然而,你可以在Jupyter中使用多个内核。本文将解释如何安装和使用新的内核,并举例说明这有什么用。
默认设置
有多种方法来运行Jupyter笔记本,但如果你使用经典的Jupyter笔记本或JupyterLab服务器作为你的环境,你通常会创建一个设置,其中Jupyter代码和你自己的笔记本代码将使用相同的Python环境。但这并不是架构的要求。为了说明这一点,我将带领你完成基本环境的设置。
初始设置
在你的工作站上设置 Python 有很多选择。我推荐使用pyenv或anaconda。如果你想跟着学,首先用这两个工具中的任何一个创建一个虚拟环境 (如果你有喜欢的方式来设置虚拟环境,也可以使用其他工具)。
创建环境
在这里,我将为这个演示创建virtualenv。它将使用Python 3.10.4,我把它叫做kernels :
$ pyenv virtualenv 3.10.4 kernels
$ pyenv activate kernels
现在,我们要在virtualenv中安装jupyter笔记本进程:
$ pip install jupyter
在这一点上,你有一个安装了jupyter基础设施的Python virtualenv,你可以启动笔记本进程。如果你想使用JupyterLab,你只需按照JuptyerLab的说明进行安装并启动它:
$ jupyter-notebook
你应该看到一个浏览器窗口启动,如果没有,你会在终端看到本地服务器的URL。你可以在你的浏览器中拉出这个网址,现在你就有了默认的Jupyter环境。从这里,你可以创建并启动一个新的笔记本进程。你可以通过选择 "新建 "按钮下的内核来实现这一目的。

只有默认的内核显示出来
注意,这里只有一个笔记本选项,而且是Python 3内核。事实证明,选择这个内核将使用启动Jupyter笔记本服务器的同一个Python环境来创建和启动一个新的笔记本。它目前是一个光秃秃的Python虚拟环境,里面安装了jupyter 及其所有的依赖项。如果你使用这个内核运行一个笔记本,它将可以访问Python核心库,但也会安装Jupyter的依赖项。
依赖关系
假设你想创建两个不同的笔记本。一个可能是用于数据分析,需要pandas和numpy。另一个可能需要访问一个数据库并对数据进行一些计算。你有什么选择?
- 在
kernelsvirtualenv中安装所有的依赖项,然后运行这两个笔记本。 - 在
kernelsvirtualenv 中创建第一个笔记本,然后为第二个笔记本创建另一个virtualenv。 - 为每个笔记本创建一个virtualenv,但把它们安装成内核。
我将走过这三条,以便你理解为什么每条都会成功。
全部放在一起
第一个选项,把所有东西放在一个virtualenv中,对于大多数使用情况来说是很有意义的。你为你的项目创建一个virtualenv,在其中安装jupyter工具,然后只需pip install (或conda install )你需要的依赖项。在许多情况下,这将是很好的工作。我想,我们大多数人都是这样做的。
每个笔记本的虚拟环境
第二种选择实际上与第一种选择相同,但是当你不想共享依赖项时,你做出了分离虚拟环境的决定。关于这个选择需要注意的是,Jupyter工具(及其依赖)都是两个虚拟环境的一部分。
每个笔记本一个内核
这最后一个选项是不同的。通过为特定的使用情况创建一个虚拟环境(和内核),你可以对依赖关系进行细粒度的控制。为什么我们想要这种额外的复杂性?
- 你的笔记本对于相同的依赖关系有不同的版本要求,但你想运行一个Jupyter实例。
- 你想用多个版本的Python(或多个版本的依赖关系)运行或测试你的代码。
- 你在一个较大的工作组中,运行类似JupyterHub的东西,在那里多个用户共享一台服务器。用户需要特定版本的依赖项,不能共享一个环境。
我相信你能想到更多的情况,这可能是有价值的。
如何添加一个内核
现在我们来看看添加另一个内核的过程。像以前一样,我们将创建一个virtualenv,但在这种情况下,我将使用不同版本的Python并在其中安装不同的依赖:
$ pyenv virtualenv 3.8.7 kernel-ds
$ pyenv activate kernel-ds
$ pip install pandas numpy
现在,我们有了virtualenv,我们需要把它作为一个内核加入。内核可以为单个用户安装,也可以为整个系统安装。注意,你要传入--name 和 -display-name 参数,这样你就可以很容易地分辨出内核的不同,这样你就不会覆盖现有的内核了:
$ python -m ipykernel install --name "ds" --display-name "Data Science Kernel"
要查看你的环境中可用的内核,你可以列出它们:
$ jupyter kernelspec list
Available kernels:
python3 /Users/mcw/.pyenv/versions/3.10.4/envs/kernels/share/jupyter/kernels/python3
ds /usr/local/share/jupyter/kernels/ds
如你所见,现在有两个内核可用。内核在一个JSON文件中进行了描述:
$ cat /usr/local/share/jupyter/kernels/ds/kernel.json
{
"argv": [
"/Users/mcw/.pyenv/versions/kernel-ds/bin/python",
"-m",
"ipykernel_launcher",
"-f",
"{connection_file}"
],
"display_name": "Data Science Kernel",
"language": "python",
"metadata": {
"debugger": true
}
}
如何使用内核
现在你可以通过在你的Jupyter笔记本环境中的 "新 "下拉菜单中选择内核来使用它。如果你正在使用JupyterLab,它将显示在新笔记本的可用内核中。新的笔记本使用你选择的环境。

新安装的内核现在是可用的。
这在你的工作站上是什么样子的?查看这个的一个方法是通过unixps 命令。这将列出你的机器上运行的进程。下面是我启动两个新的笔记本后的情况,每个笔记本都使用了可用的内核。
$ ps -e | grep python | grep -v grep # show all python processes, but filter out the grep command itself
501 49397 49381 0 4:46PM ?? 0:01.42 /Users/mcw/.pyenv/versions/kernel-ds/bin/python -m ipykernel_launcher -f /Users/mcw/Library/Jupyter/runtime/kernel-b021fef2-b947-4cdd-8448-4caf1df085dc.json
501 49403 49381 0 4:46PM ?? 0:00.76 /Users/mcw/.pyenv/versions/3.10.4/envs/kernels/bin/python3.10 -m ipykernel_launcher -f /Users/mcw/Library/Jupyter/runtime/kernel-ac0c95a1-5527-4df2-9448-1435e4d16636.json
501 49381 43796 0 4:46PM ttys004 0:02.16 /Users/mcw/.pyenv/versions/3.10.4/envs/kernels/bin/python3.10 /Users/mcw/.pyenv/versions/kernels/bin/jupyter-notebook --no-browser
第二栏是进程ID,第三栏是父进程ID。你可以看到最后一个进程(pid 49381)是jupyter-notebook进程本身。它是在kernels virtualenv中运行的。其他两个进程(49397,49403)都有相同的父进程id,但使用两个不同的virtualenv来运行它们的内核。
缺点
在我们结束之前,我想指出我注意到的几个问题:
首先,如果你用--user 选项创建的内核与全局安装的内核名称相同,用户版本似乎会优先考虑并隐藏全局选项。因此,如果你使用这个工具,重要的是要对命名规则有一个聪明的认识,这样你就不会最终对你的依赖关系的安装位置感到困惑。
第二,添加其他内核类型是在排除问题时需要考虑的另一个变量,可能会引起一些额外的混乱。即使是在创建这些例子时,我也有几次混淆了。在许多简单的设置中,你可能只需要使用virtualenvs来跟踪依赖关系就可以了,但是对于许多情况,拥有多个内核是一个非常优雅的解决方案。也许你可以在你的环境中使用这个方法。