• 我为什么使用conda而不是pip?
  • 发布于 2个月前
  • 166 热度
    1 评论
  • 巴克利
  • 30 粉丝 47 篇博客
  •   
为什么使用conda而不是pip?
如果你是搞科学的就会知道,打包是一个多语言问题。你可以使用基于系统的非python库安装,但是如果你想要处理依赖于这些工具的多个版本的多个项目,那么通常就会遇到一些问题。此时Conda就几乎成了唯一的出路。况且,Anaconda还有针对Intel MKL(数学内核库)编译的包。这同样也会使性能变得更快。
pip构造更慢一些


停止使用根环境

当人们开始使用conda/anaconda时,他们倾向于使用根环境(安装程序创建的环境)来做所有的事情。接着,他们开始在里面安装很多东西,直到根环境崩溃,最终束手无策。

相比之下,为每个项目创建独立环境要容易得多。如果你搞砸了,你可以很方便地删除它们,然后重新开始。根环境是用来安装conda的地方。说真的,你的根环境应该只用于升级conda。其他所有事情都交给其他环境来做,这样你的编程生活才会更加长久的幸福。

开始使用Conda构造器
如果你想要为一组用户管理anaconda环境,构造器会是一个很好的工具! 在OSX/Linux/Windows上用于安装Anaconda和miniconda的安装程序是使用构造器构建的。构造器允许使用不同的规范来构建自己的安装程序,因此你不再需要依赖anconda安装程序,并且你可以根据团队所需的数据科学环境来构建安装程序。
使用构造器创建的安装程序是部署生产应用程序的一种很不错的方式。安装文件往往比较大(因为所有二进制文件都被打包到可执行文件中),但好处是安装时不需要依赖网络。

Conda构造器不能在noarch包上工作——这可能会造成一些不便。(noarch包是一组独立于平台的包——代表着你为linux/osx和windows构建了一个包)。其实有很多库(比如django)看似是独立于平台的,但实际上依赖于一些平台特定的包。


不要过分依赖于修改环境
通常情况下,构建环境并丢弃它们比无止境地修改要好的多。个中缘由是一个环境最终会进入一种奇怪的状态。我知道这听起来很糟糕——发生这种情况的主要原因是,随着时间的推移,你会不停地升级conda,但它很可能会与旧的环境不兼容。另外,随着时间的推移,你还会不停地修改环境,而环境通常又会继续成长,这使得conda最终变得不可理喻(而且运行更慢)。

小心使用NFS
系统管理员和devops通常会为多用户安装集中的conda环境。这些环境会有一些缓存包作支持,而这些缓存包一般会存在于这个世界上一个可读但不可写的位置。当用户创建自己的conda环境时,最终会在自己的主目录中下载自己的包(这是通常情况,因为他们没有权限写入到系统管理的缓存包中)。Conda可以从多个缓存包中对包进行符号链接,这当然很好。但是如果主目录挂载了NFS后,当用户试图在多台机器上使用自己的环境,而这些机器并没有相同的缓存包时,问题就会随之产生。

在机器A上,我在/opt/anaconda下有一个集中安装的anaconda。它包含 zeromq=4.2.5=hf484d3e_1。所以当我在~/.conda中创建自己的环境时,那个包就会被符号连接到我的环境中。但是,如果我尝试在机器B上使用这个环境,其中缓存包不包含 zeromq=4.2.5=hf484d3e_1,那么我的环境就会崩溃。


你有几个选择
1、始终确保每台机器上集中的环境是相同的
2、在conda中禁止符号链接
我的建议是这两者都要做。拥有相同的集中式环境这个主意相当好,这意味着无论用户走到哪里,他们都会得到相同的东西。此外,在共享环境中,禁用符号链接非常有用,因为如果你曾经升级过中心环境,那么你最终可能会(通过删除包)破坏用户环境。

生产环境中不要太担心conda激活器
Conda 激活器负责设置路径和一些环境变量,这些环境变量会告诉Conda应该将内容安装到哪个环境中。在部署应用程序时,这肯定会分散你的注意力。当部署应用程序时,在你的启动脚本中引用二进制文件的绝对路径要比调用激活器要容易得多。编辑:通常这是正确的,但是我听说有些包(pyspark/rpy2)依赖于这个路径。

在部署生产环境时,永远不要试图解析依赖关系
你可以编写一个依赖于scikit-learn的应用程序,可以为应用程序构建一个conda清单,以便将其部署到生产环境中。这不是你的第一次上战场,你做出了明智的选择,然后一切就开始了,你设置
 - scikit-learn=0.20
到你的清单中。非常棒! 但是请注意,scikit-learn还依赖于
- scipy
而且无需指明它依赖于哪个版本。如果你使用scipy 1.1.0进行测试,然后当你要部署scipy 1.2.0时,conda solver将会自动使用最新的版本,这样你的生产环境就是1.2.0版本,这样还省却了程序的兼容性测试。
如果要确保所有嵌套的依赖关系都在生产之前完全解决。有两种方法可以做到这一点。一种是使用conda env export来精确导出每一个想要部署的包的规范(精确到构建号)。这一切的动作必须发生在与生产环境部署相同的平台上。另一种方法是使用构造器。构造器好就好在安装用构造器构建的东西时,不需要再对conda存储库有依赖。唯一的缺点是,由于所有东西都被塞到构造器安装程序中,所以你要部署的文件大小通常至少是几百兆字节,可能是几千兆字节。

如果我需要的包不在Anaconda里呢
首先检查Conda Forge。Conda Forge是一个用来构建所有东西的社区项目。有很大几率你需要的包就在那里,可以通过conda命令
conda -c conda-forge install my_package.
指定conda-forge通道来安装它。
如果失败了——你可以使用conda skeleton从pypi包中生成一份conda清单。同时你还需要构建并上传包到你自己的存储库中,因此这可能会很麻烦。

如果觉得构建自己的包太繁琐,推荐使用pip。我这样做是为了做探索性的工作。无论怎样,我都建议你在发布到生产环境之前先构建适当的conda包。这样做的原因是,对于不能完全依赖于pip的部署中,在进行部署(使用anaconda构造器或conda env导出)之前,确保你的依赖关系已经完全解决。


用户评论