拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Jupyter Notebook多环境管理:一环境一内核配置指南

Jupyter Notebook多环境管理:一环境一内核配置指南 Jupyter Notebook 应该是数据分析、机器学习、教学演示里用得最多的交互式工具了。但用久了你会发现一个很头疼的问题不同项目的依赖经常互相打架。项目 A 要用 pandas 1.x项目 B 非要 pandas 2.x今天给一个环境装了个新包明天另一个项目跑起来就报 ImportError甚至整个环境直接崩掉。更麻烦的是Jupyter Notebook 默认只加载启动它时的那个 Python 环境你辛辛苦苦在 conda 里建好了好几个虚拟环境打开 Notebook 一看内核列表里永远只有 base其它环境一个都找不到。这篇文章要解决的就是这个问题——用一环境一内核的方式让 Jupyter Notebook 在不同虚拟环境之间自由切换每个项目都有自己干净、独立、随时能复现的运行环境。文章会从内核机制讲起给出 conda 和 venv 两套环境的完整配置步骤把内核注册命令的每个参数拆开说明再附上我踩过几次坑之后的排查经验和进阶玩法。不管你是刚接触 Notebook 多环境的新手还是被环境冲突坑过多次的熟手这篇文章里的方案基本都能直接抄作业。1. 先搞懂 Jupyter 的内核是个什么东西1.1 内核与 Notebook 服务器的关系在配置多环境之前我建议你先搞清楚 Jupyter Notebook 的运行机制。Jupyter Notebook 看起来是个网页你在浏览器里敲代码、点运行以为代码是在网页里执行的——其实不是这么回事。它的完整链路是这样的浏览器里的网页只是前端界面负责展示代码、接收输入、渲染输出真正干活的进程是后台的一个内核Kernel。你点运行按钮时代码通过 ZeroMQ 协议被发到内核进程由内核执行完毕后把结果返回给前端前端再把输出渲染成你看到的 Markdown、图表、表格等等。这个机制有一个对多环境配置至关重要的推论内核进程是不绑定 Notebook 服务器的。也就是说启动jupyter notebook时用的 Python 环境和实际执行代码的内核环境可以是完全不同的两套环境。只要某个 Python 解释器里装了ipykernel并且把自己的信息注册到了 Jupyter 的配置目录里它就能被 Jupyter 识别为一个可选内核。你切换内核本质上就是切换执行代码的 Python 解释器和它背后的那一整套第三方包。理解了这一点后面所有的操作就顺理成章了。所谓多环境配置核心工作就两步先把不同的虚拟环境创建好再把每个环境注册成 Jupyter 的内核。1.2 为什么一环境一内核比一个 base 打天下更靠谱很多刚接触 Python 的人有个习惯包不够用了就pip install不管装到哪个环境里反正能跑就行。这种一个 base 打天下的方式在项目少、依赖简单的时候没什么问题但一旦项目多起来早晚出事。举个我实际遇到的例子有一个项目要求 numpy 必须用 1.21 版本因为旧代码用了np.float这类在 numpy 1.24 之后被移除的别名另一个项目则需要 numpy 2.x 来跑新版的深度学习框架。如果你把它们装进同一个环境结局必然是装完一个另一个就崩。类似的情况在 TensorFlow / PyTorch、Python 3.7 / 3.10、OpenCV 各种版本之间都特别常见。虚拟环境的作用就是给每个项目划出一块独立的房间房间里的包互不干扰。而 Jupyter Notebook 作为很多项目的前台入口如果你没办法在每个项目对应的环境里运行代码那环境隔离得再好也没用。一环境一内核就是把房间和前台打通每个房间装一个对应内核打开 Notebook 时随口一换就能进入正确的房间干活。这比我以前那种用完一个环境再切出去创建另一个的工作流要顺滑太多。2. 环境准备创建虚拟环境是第一步2.1 conda 方案适合数据科学全家桶如果你主要做数据分析、机器学习或者你本来就是因为 Anaconda 才接触的 Jupyter那用 conda 创建环境应该是最顺手的路径。先说为什么推荐 conda 而不是裸 venv。conda 的包管理不仅限于 Python 包还能管理 numpy、scipy、opencv 这类带有二进制编译产物的底层库。这类包用pip安装时经常出现编译不过依赖库缺胳膊少腿的问题而 conda 会直接拉取官方预编译好的二进制包在 Linux 和 macOS 上尤其省心。另一个好处是 conda 在创建环境时可以直接指定 Python 版本比如你需要跑一个只能用 Python 3.7 的旧项目直接conda create -n py37 python3.7就解决了不需要你自己去下载安装特定版本的 Python。具体操作如下# 创建环境并指定 Python 版本这里以 3.9 为例 conda create -n myenv python3.9 -y # 激活环境 conda activate myenv # 在目标环境里安装 Jupyter Notebook 和内核支持 conda install jupyter ipykernel -y注意这里有个很关键的细节conda install jupyter这个操作是在目标环境内部执行的不是在你的 base 环境里执行。这样会让目标环境自带一套 Jupyter Notebook这个 Notebook 启动时用的就是当前环境是最干净的一种状态。如果你依赖都已经装在 base 里目标环境只装了 ipykernel那 Jupyter Notebook 服务器本身仍然由 base 启动只是内核切换到了目标环境——这种情况也能用但某些时候会出现base 里的包污染可视层的错觉我后面会专门讲这个坑。2.2 venv 方案轻量且 Python 原生如果你不喜欢 Anaconda 那种动不动几个 G 的体量或者你只想给某个小项目开个独立空间用 Python 自带的venv模块就足够了。venv 是 Python 3.3 之后内置的虚拟环境方案使用起来非常简单# 创建虚拟环境 python -m venv myenv # 激活环境Windows 下命令不同 source myenv/bin/activate # Linux / macOS myenv\Scripts\activate # Windows # 安装内核支持和 Notebook pip install jupyter ipykernelvenv 的优势是轻、快、零额外依赖而且它直接复用你当前系统的 Python 解释器版本在某些只需要隔离第三方包、不需要隔离 Python 版本的场景下比 conda 更轻量。但它的短板也很明显它无法帮你管理 Python 版本本身如果你需要 Python 3.7 和 Python 3.10 并存venv 就无能为力了这种情况建议还是用 conda或者用 pyenv 这类专门管理 Python 版本的工具。2.3 两种方案怎么选我自己的经验是凡是涉及数据科学、深度学习、科学计算的项目优先 conda因为它能解决底层二进制依赖凡是纯 Python 的 Web 项目、脚本项目、或者我仅仅是临时想验证一个想法就用 venv因为它创建速度快、占用小。两条路最终的指向是一样的——创建好环境后把环境注册为 Jupyter 内核然后在 Notebook 里切换。这里顺便说一句不管用哪种方案我都建议你给环境起一个能一眼看懂的名字。比如项目名、项目名Python 版本像myproject-py310比env1、test这种名字要强太多。内核显示名也可以在注册的时候自定义稍后会说到。3. 内核注册与切换的核心操作3.1 注册内核的完整命令与参数拆解环境创建好、依赖装完之后接下来就是核心操作把当前环境注册成 Jupyter 内核。先在目标环境里确认激活状态确保当前 shell 指向的是你要注册的环境。然后执行这条命令python -m ipykernel install --user --name myenv --display-name Python (myenv)如果你在 Windows 的命令行里执行语法是一样的。下面把参数逐一说清楚因为很多人就是在这几个参数上栽了跟头。python -m ipykernel这句表示用当前环境的 Python 解释器来运行 ipykernel 模块。注意必须确保你conda activate或source activate进了目标环境之后再来执行否则它用的可能是 base 里的 Python。install告诉 ipykernel 把内核信息写入 Jupyter 的内核目录。--user表示把内核注册到当前用户的 Jupyter 配置目录。不加这个参数时有些系统会尝试写到系统级目录需要管理员权限容易失败。加上--user通常能规避权限问题。--name这是内核的内部标识名也是存放内核配置文件的文件夹名。它不会直接显示在 Notebook 界面上但不能和现有内核重名。--display-name这是你在 Notebook 界面的内核下拉列表里看到的名字。你可以把它改成我的数据分析环境这种好认的名字完全不影响内核本体只是显示用。注册成功后终端会显示类似Installed kernelspec myenv in ...的信息这就表示成功了。你可以用下面的命令查看当前机器上一共注册了哪些内核jupyter kernelspec list输出会列出所有内核的名字和路径。到这里内核注册的完整流程就结束了前后不超过一分钟但很多人第一次配环境时都会卡在这一步最常见的原因就是忘了激活环境就直接执行了后面我会专门讲排查方法。3.2 在 Notebook 界面里完成内核切换内核注册好了打开 Jupyter Notebook 就能看到效果。启动方式还是老样子只是需要注意从哪个环境启动。如果你是先激活了目标环境再在目标环境里安装了 jupyter然后执行jupyter notebook那启动的服务器和默认内核都是目标环境自身的。如果你是在 base 环境里启动的 Jupyter那么默认内核会是 base但你可以从下拉列表里找到刚注册的myenv环境。切换的方式有两种新建 Notebook 时在New下拉菜单里选择目标内核比如Python (myenv)新建出来的 notebook 实例就直接运行在对应环境里。已经打开的 Notebook右上角Kernel菜单里选择Change Kernel然后从列表里选要切换的环境。这个操作不需要重启 Jupyter 服务器只要内核被切换后续的代码就会在新的环境里执行。切换之后我建议你做一次快速体检确认自己真的在用目标环境。方法也很简单新建一个单元格执行以下代码import sys print(sys.executable)如果输出的路径指向你 conda 环境目录下的python.exe或bin/python就说明切换成功了。还可以再跑一句import pandas print(pandas.__version__)这能在最早阶段暴露包装错环境这一类问题。3.3 批量注册多个环境的快捷脚本如果你的工作流里经常有几个固定的环境每个都手动执行一遍注册命令虽然不难但也挺烦人。我习惯写一个小脚本来批量处理。下面是一个在 bash 环境Linux / macOS / Git Bash下可用的示例它会把当前机器上已有的 conda 环境列表读出来逐个安装 ipykernel 并注册for env_name in myenv1 myenv2 myenv3; do conda run -n $env_name pip install ipykernel -q conda run -n $env_name python -m ipykernel install --user --name $env_name --display-name Python ($env_name) doneWindows 用户如果用 PowerShell可以换个写法$envs (myenv1, myenv2, myenv3) foreach ($env in $envs) { conda run -n $env pip install ipykernel -q conda run -n $env python -m ipykernel install --user --name $env --display-name Python ($env) }这里用到了conda run -n env_name作用是临时在指定环境里执行命令省去了反复激活再注销的麻烦。批量注册完后同样用jupyter kernelspec list验证一下。以后新加一个环境就照样子往列表里加一行命令即可。不过也要提醒一句conda run在部分 Windows 老版本上有输出延迟的毛病如果你执行后半天看不到输出不是卡死了是 conda 在等待子进程结束。遇到这种情况耐心等一下就行或者改用conda activate后再逐条执行。4. 常见问题与排查技巧实录4.1 内核列表里看不到目标环境这是被问得最多的一个问题环境明明创建了注册命令也执行了但打开 Jupyter 后新建下拉列表和 Change Kernel 列表里就是看不到对应的环境名。排查思路要按顺序来。先执行jupyter kernelspec list看看内核是否真的注册成功。如果列表里根本没有你注册的名字那就是注册环节出了问题。最典型的原因是执行注册命令时没有激活目标环境导致python指向的是 base 环境注册出来的内核实际上是 base 的名字也自然不对。解决方法是先conda activate myenv确认命令行提示符前多了(myenv)之后再重新安装 ipykernel 并注册。如果jupyter kernelspec list里能看到名字但 Notebook 界面里看不到那问题多半出在 Jupyter 的内核发现路径上。Jupyter 会从多个目录搜索内核--user参数安装到了当前用户目录某些情况下可能和你启动 Jupyter 的用户不一致。最简单的验证方法是在 Jupyter Notebook 里新建一个单元格执行!jupyter kernelspec list如果这里能看到目标内核但界面下拉列表里没有一般是因为 Jupyter 服务器没完全刷新。你可以刷新浏览器页面或者干脆重启一次jupyter notebook进程。还有个少见但容易忽略的原因如果你在 notebooks 服务器里修改了jupyter_notebook_config.py中c.KernelSpecManager相关的路径设置也可能导致内核目录不匹配这时候检查一下配置文件里的路径就行。4.2 切换内核后还是用的错误环境这个问题比上一种更隐蔽内核列表里能看到目标环境切换后代码也能运行但sys.executable指向的路径就是不对或者某些包只有目标环境里装了却报 ModuleNotFoundError。遇到这种切换了个寂寞的情况最可能的原因是注册时用了错误环境的 Python 去注册。我举个例子你本想给myenv注册内核但执行命令的时候忘了激活环境使用的是python -m ipykernel install这里的python来自 base所以即使--name myenv写的是目标环境内核配置文件里记录的解释器路径实际是 base 的 Python。打开 Notebook 后你看到Python (myenv)但点进去执行代码用的其实是 base。怎么排查直接用上面 3.2 节的方法执行import sys; sys.executable看路径。如果确实指向了错误环境先删掉这个错误的内核再重新注册jupyter kernelspec remove myenv然后激活正确的环境重新执行安装 ipykernel 和注册内核的命令。这一步有个值得养成的习惯注册完成之后立刻动手验证一次不要等到代码开始跑才发现环境不对。省下来的时间远远超过那一分钟。4.3 conda 环境里的包在 Notebook 里 import 不到这个问题有一种很典型的误解决方式你已经用conda install pandas在目标环境里装了包但在 Notebook 里import pandas却报错找不到。很多人会下意识地继续往目标环境里pip install结果一直没用。实际原因大概率是内核指向的 Python 不是目标环境的 Python。你可以在 Notebook 里跑一下sys.executable和sys.path看看这两者的输出是否指向目标环境的目录。如果sys.executable指向的是/opt/anaconda3/bin/python而你的环境在/opt/anaconda3/envs/myenv/bin/python那就说明内核注册错了或者 Jupyter 服务器是用 base 里的 jupyter 启动的内核注册时用的是python -m ipykernel但没用好。另一个常见原因是环境路径移动过。比如你换了一台电脑直接把之前的 conda 环境目录整个拷过来注册旧内核时kernel.json里的/path/to/env/bin/python已经不存在了。这时候看 Notebook 的内核报错通常会出现FileNotFoundError或内核反复重启。解决办法也很直接删掉旧内核用新的环境路径重新注册。4.4 内核启动报错处理速查Jupyter 切换内核后有时候会弹出Kernel Restarting、The kernel appears to have died之类的错误日志栏里明确写着原因。这里整理一个速查表能覆盖我见过的大多数情况。报错或现象可能原因解决方法ModuleNotFoundError: No module named ipykernel内核环境里没装 ipykernel激活环境后执行conda install ipykernel或pip install ipykernelFileNotFoundError: python 路径不存在环境目录被移动或删除删除旧内核jupyter kernelspec remove然后重新注册内核无限重启日志无明确错误代码本身崩溃或前端与内核通信异常先用简单的print(test)排除业务代码问题再检查 Jupyter 和 ipykernel 版本import 目标包时版本不对切换后仍然加载旧环境的包检查sys.executable确认在正确环境里重新注册Notebook 页面卡住点击执行无响应内核进程被杀或网络端口被占用重启 Jupyter 服务必要时重启电脑检查是否开了代理或防火墙拦截了本地端口还有一个小技巧当你遇到内核反复重启并且怎么排查都找不出问题时可以考虑给 Jupyter 打开详细日志。启动时用jupyter notebook --debug这样终端里会打出非常详细的内核启动过程报错原因一般会直接暴露在最后几十行里。这个方法看起来笨但排查严重问题时往往比猜快得多。5. 进阶玩法让多环境管理更省心5.1 用 nb_conda_kernels 自动发现 conda 环境前面讲的手动注册是一种显式的管理方式环境多了每次都要手动执行一次注册还要维护一张环境清单。其实还有一个更省心的方案——用nb_conda_kernels这个包它会自动扫描机器上所有的 conda 环境然后在 Jupyter 界面里生成对应的内核入口。具体做法是只在 base 环境里安装nb_conda_kernels然后确保其它每一个环境里都安装了ipykernel。当你启动 Jupyter 时nb_conda_kernels会自动检测到所有满足条件的环境并生成Python (env: myenv)这样的选项。你不需要手动执行ipykernel install也不需要关心--name和--display-name一切由插件自动完成。conda activate base conda install nb_conda_kernels -y这个方案的优势是一次配置长期自动。我在团队协作的场景下很喜欢用它尤其是多人共用同一台开发机时新同事不需要学习一个个环境注册的命令只要把他的 conda 环境装好 ipykernel界面上自然就会出现。不过要注意它只对 conda 环境生效venv 创建的环境不会被自动发现。5.2 结合 Jupyter Lab 与 VS Code 的多环境管理说完了传统 Jupyter Notebook再提两个我在实际工作中很常用的扩展场景Jupyter Lab 和 VS Code。Jupyter Lab 是 Jupyter 官方推出的下一代界面多环境管理逻辑和 Notebook 一脉相承。启动命令就是jupyter lab打开后你会发现界面上有Choose Kernel的按钮列出所有已注册内核如果你的机器装了nb_conda_kernelsconda 环境也会一并出现在列表里。右侧的Properties面板还能直接查看当前内核路径、Python 版本、包数量等信息比传统 Notebook 要直观得多。VS Code 的情况也类似。你不需要通过浏览器访问 Jupyter而是用 VS Code 连接本地或远程的 Jupyter 服务器。在.ipynb文件右上角会有一个内核选择器点击后可以选择Python Environments里的任意一个 conda 或 venv 环境前提是你已经在 VS Code 里安装了 Python 扩展和 Jupyter 扩展。这种方式适合整天泡在编辑器里的人切换内核的体验和浏览器端几乎一样。唯一需要注意的是VS Code 在远程开发比如 SSH 连服务器时不光要让它能连上 Notebook还要确保远程机器的内核注册目录对它可见否则会找不到内核。5.3 用 requirements 与 environment.yml 做到环境可复现最后一个建议是给多环境配置加一层保险环境可复现。不管你用 conda 还是 venv都要有导出依赖清单的习惯。conda 环境的导出方式conda activate myenv conda env export environment.ymlvenv 环境可以用 pip 导出pip freeze requirements.txt这样做的好处是如果哪天环境崩了、换机器了、或者同事需要复现你的项目拿着这个文件几秒就能重建环境。这里我踩过一个坑conda env export在某些情况下会包含build字段比如numpy1.26.0py310h0ad8c1a_0导致在另一台不同架构或系统的机器上重建时直接报错。如果你只需要包名和版本范围更稳妥的方式是用conda env export --from-history这样只会导出你显式安装的包不会带上系统依赖和 build 标识。放到项目里时我习惯把environment.yml或requirements.txt放在项目根目录然后在项目的 README 里写一行说明告诉别人先用这个文件建环境再把环境注册成 Jupyter 内核。这样整个团队的新成员上手速度会快很多也不容易出现我明明照着文档配了怎么跑不起来的情况。你在实际操作里也可以考虑把小技巧组合起来新环境创建之后第一件事就是立刻注册内核然后验证sys.executable和关键包的版本项目稳定之后再导出依赖清单。流程固定下来后面基本不会出大问题。我后来维护的每个项目环境、内核、依赖清单三件事都是一体的后续几个月几乎不用再碰环境配置了。
返回列表