Conda你真的可以去死了
作为最常见的Python跨平台的包管理和环境管理工具,Conda的使用体验真的让人一言难尽...
前言
涉及到Conda开发的往期文章:
作为最常见的Python跨平台的包管理和环境管理工具,Conda的使用体验非常糟糕,这一次配环境和看Github上issue的经历实在是让我愤怒到想要写一篇文章来痛斥Conda。
万恶之源:Solving Environment
这一次需要配的Conda环境来自Mega-NeRF,事情的导火索来自其初始化步骤的:
conda env create -f environment.yml
而这份yml文件的配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name: mega-nerf
channels:
- pytorch
- conda-forge
- defaults
dependencies:
- _libgcc_mutex=0.1=main
- _openmp_mutex=4.5=1_gnu
- absl-py=1.0.0=pyhd8ed1ab_0
- aiohttp=3.7.4.post0=py39h3811e60_0
- async-timeout=3.0.1=py_1000
- attrs=21.2.0=pyhd8ed1ab_0
- blas=1.0=mkl
- blinker=1.4=py_1
- brotlipy=0.7.0=py39h3811e60_1001
- bzip2=1.0.8=h7b6447c_0
- c-ares=1.17.1=h27cfd23_0
# 这玩意太长就不接着列了
看上去是比较友好的,与前面配的逆天环境不同的是,它给出了很详细的版本号,甚至说精确到了hash的地步,但是一开始装就开始卡死在Solving Environment,我估计又像之前一样存在冲突了。
从mamba到libmamba
然后这次,想要试试yml安装/更新的方法,把yml简化到了基本不能再简化的地步。
1
2
3
4
5
6
7
8
9
10
name: mega-nerf
channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- pytorch
- conda-forge
- defaults
dependencies:
- python=3.9
- cudatoolkit=11.3
- pip
这里还是把cuda留这了,因为cuda这玩意还是Conda装比较好,但是依旧卡死。由于mega几乎没有env的问题汇报,基本可以断言是Conda而非环境的问题,准确来说就是Conda的solver炸了。
用经典的指令检查了一下目前装在服务器的Anaconda版本,得到的结果是22.9.0,就是说是22年的老东西。
在前面的文章中一笔带过了mamba,它包含了一个相对于Conda而言更有效的solver,有些conda反解不出来或者解起来比较费事的库,用mamba来解就会好很多。抱着这个念头,我想着试试要不要去装个mamba。
给出的安装程序是这样的:
conda install -c conda-forge mamba
然后,不出意料的,这个程序同样卡在了Solving Environment,意味着mamba与当前Conda的已知库是不兼容的。这个问题在网络上有相同的汇报,解决方案是本地安装。
使用Pip安装的mamba是使用不了的,有着更多的兼容性问题,比如甚至会把environment.yml
这一条识别成一个“库”,实在不可理喻。
经过检索,有着另外一个替代方案,就是仅仅使用mamba中的solver:libsolv,同样能够提高速度。安装的方法为:
1
2
conda install conda-libmamba-solver
conda config --set solver libmamba
但第二条是不可用的,提示是:
CondaValueError: Key 'solver' is not a known primitive parameter.
在libmamba的faq有着针对这一问题的解释,里面写道“建议使用22.12版本以上的libmamba,否则,应该使用的参数是experimental_solver”。
于是又把参数换成了experimental_solver,然而还是不可用,在base(基环境)中尝试使用libmamba时,指出:
CondaEnvironmentError: LibMambaSolver is not allowed on the base environment during the experimental release phase. Try using it on a non-base environment!
版本自锁
于是,现在我有两条路走,要么试着用上更新的libmamba,那么需要更新Conda;要么就在需要的环境里面单独配个libmamba,而后者显然是我不期待的(这意味着如果每次都解析出错的话,那么我需要在每个环境中都配一个,无疑是重复的多余工作)。
However,当我尝试用最经典的指令更新Conda时,发生了很诡异的事情:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(base) 【实际路径】$ conda update -n base -c defaults conda
Collecting package metadata (current_repodata.json): done
Solving environment: done
==> WARNING: A newer version of conda exists. <==
current version: 22.9.0
latest version: 25.5.2
Please update conda by running
$ conda update -n base -c defaults conda
# All requested packages already installed.
Retrieving notices: ...working... done
就是说,我用标准update更新过后,居然还让我检查是否更新,这意味着根本就没有执行更新。
我怀疑是repodata.json出了问题,但更换了几个源(使用--repodata-fn=repodata.json
参数指定)之后,依旧出现此问题。就这个问题,我个人的推断是版本自锁,由于Strict Priority的问题,在解算Conda版本时无法使用更新的版本,即Conda安装上的库反向锁死了Conda自己的版本。由于强制更新Conda又会因为它出现不能降级的问题,我也没有用指定版本的方法更新。
顺着这条线索去找,在Github上面找到了类似的issue,但给出的解决方案是fresh install,我是没有权限的,所以只能作罢。
在指向它的几个issue中,我看到了这样啼笑皆非的一段话:
而关于这个问题,也确实有一个出于Planning状态的由开发团队于2024年2月创建的issue,里面包含了更多逆天的问题,虽然很大一部分都被解决了,但时至今日它依旧是left open的状态。
无奈的妥协
最后的解决方案就是,走了另外一条路,先用标准的conda create
创建了环境,引入libmamba,然后把环境顺顺利利地装上去了。
所以,故事的结局是什么?是在绕了一大圈,尝试了更新、安装新求解器、甚至想直接升级Conda本身之后,我又回到了最原始、最笨拙的办法:在一个干净的环境里,小心翼翼地引入那个本该在base环境中拯救我的mamba——它甚至自己解决不掉这个问题,还需要一个专门的mamba库。
这无疑是一种巨大的讽刺。Conda的核心问题——求解器性能和依赖解析的脆弱性——已经严重到可以阻止用户安装任何用于解决这些问题的工具。这是一个完美的死循环,一个由开发者自己挖好、然后把无数用户推下去的深坑。
这次配环境的经历,与其说是在解决Mega-NeRF的环境依赖,不如说是在和Conda这个工具本身搏斗。我花在等待Solving Environment上的时间,花在检索各种离奇bug上的时间,远比真正开发项目,去研究那些应该出现在论文里面的算法的时间要多得多。一个本应“简化”包管理和环境部署的工具,如今却成为了工作流中最复杂、最不可靠、也最浪费生命的一环。
所以,Conda,当你的基础功能已经崩溃,连用户的“自救”行为都能被你亲手扼杀时,或许真的不怪大家对你说一句:
Conda,你真的可以去死了。