文章

Conda你真的可以去死了

作为最常见的Python跨平台的包管理和环境管理工具,Conda的使用体验真的让人一言难尽...

Conda你真的可以去死了

前言

涉及到Conda开发的往期文章:

Labelme的安装使用说明

迎击mask2former

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中,我看到了这样啼笑皆非的一段话:

Cover 没有一个脏字,但是处处充满了对Conda的讥讽和无奈

而关于这个问题,也确实有一个出于Planning状态的由开发团队于2024年2月创建的issue,里面包含了更多逆天的问题,虽然很大一部分都被解决了,但时至今日它依旧是left open的状态。

无奈的妥协

最后的解决方案就是,走了另外一条路,先用标准的conda create创建了环境,引入libmamba,然后把环境顺顺利利地装上去了。

所以,故事的结局是什么?是在绕了一大圈,尝试了更新、安装新求解器、甚至想直接升级Conda本身之后,我又回到了最原始、最笨拙的办法:在一个干净的环境里,小心翼翼地引入那个本该在base环境中拯救我的mamba——它甚至自己解决不掉这个问题,还需要一个专门的mamba库。

这无疑是一种巨大的讽刺。Conda的核心问题——求解器性能和依赖解析的脆弱性——已经严重到可以阻止用户安装任何用于解决这些问题的工具。这是一个完美的死循环,一个由开发者自己挖好、然后把无数用户推下去的深坑。

这次配环境的经历,与其说是在解决Mega-NeRF的环境依赖,不如说是在和Conda这个工具本身搏斗。我花在等待Solving Environment上的时间,花在检索各种离奇bug上的时间,远比真正开发项目,去研究那些应该出现在论文里面的算法的时间要多得多。一个本应“简化”包管理和环境部署的工具,如今却成为了工作流中最复杂、最不可靠、也最浪费生命的一环。

所以,Conda,当你的基础功能已经崩溃,连用户的“自救”行为都能被你亲手扼杀时,或许真的不怪大家对你说一句:

Conda,你真的可以去死了。

本文由作者按照 CC BY 4.0 进行授权