30

我们的 Django 项目越来越庞大。我们有数百个应用程序并使用大量 3rd 方 python 包,其中许多需要编译 C。当我们需要为主要版本创建新的虚拟环境时,我们的部署需要很长时间。话虽如此,我希望从 Pip 开始加快速度。有谁知道将并行安装软件包的 Pip 分支?

到目前为止我采取的步骤:

  • 我一直在寻找一个能做到这一点但收效甚微的项目。我确实找到了这个 Github Gist:https ://gist.github.com/1971720但结果几乎与我们的单线程朋友完全相同。

  • 然后我在 Github 上找到了 Pip 项目,并开始查看分叉网络,看看我是否能找到任何提到做我想做的事情的提交。里面乱七八糟的 如果必须的话,我会分叉它并尝试自己并行化它,我只是想避免花时间这样做。

  • 我在 2011 年 DjangoCon 上看到 ep.io 的一个演讲,解释了他们的部署内容,他们提到了并行化 pip、传送 .so 文件而不是编译 C 和镜像 Pypi,但他们没有谈到他们是如何做到的或他们使用了什么。

4

7 回答 7

11

并行 pip 安装

此示例使用xargs将构建过程并行化大约 4 倍。您可以使用下面的 max-procs 增加并行化因子(使其大约等于您的内核数)。

如果您正在尝试例如加快您一遍又一遍地执行的成像过程,那么直接在结果上进行成像而不是每次都这样做可能会更容易并且肯定会降低带宽消耗,或者使用pip构建图像-tvirtualenv

并行下载和安装软件包,一次四个:

xargs --max-args=1 --max-procs=4 sudo pip install < requires.txt

注意: xargs 在不同的 Linux 发行版上有不同的参数名称。检查您的发行版的手册页以获取详细信息。

使用here-doc内联的相同内容:

 cat << EOF | xargs --max-args=1 --max-procs=4 sudo pip install
 awscli
 bottle
 paste
 boto                                                                         
 wheel
 twine                                                                        
 markdown
 python-slugify
 python-bcrypt
 arrow
 redis
 psutil
 requests
 requests-aws
 EOF

警告:如果多个 pip 尝试在完全相同的时间安装相同的依赖项,则此方法的速度可能会混淆包清单(取决于您的发行版),但如果您只在 4一次。可以很容易地修复它pip install --uninstall depname

于 2015-04-14T02:44:14.803 回答
11

基于 Fatal 的回答,以下代码执行并行 Pip 下载,然后快速安装包。

首先,我们将包并行下载到分发(“dist”)目录中。这很容易并行运行,没有冲突。打印出来的每个包名都是在下载前打印出来的,有助于调试。如需额外帮助,请将 , 更改-P9-P1, 以按顺序下载。

下载后,下一条命令告诉 Pip 安装/更新包。文件没有下载,它们是从快速本地目录中获取的。

它与当前版本的 Pip 1.7 兼容,也与 Pip 1.5 兼容。

要仅安装一部分软件包,请将“cat requirements.txt”语句替换为您的自定义命令,例如“egrep -v github requirements.txt”

cat requirements.txt | xargs -t -n1 -P9 pip install -q --download ./dist

pip install --no-index --find-links=./dist -r ./requirements.txt
于 2015-06-05T17:54:57.683 回答
9

您是否分析了部署过程以了解时间真正花在了哪里?令我惊讶的是,运行多个并行 pip 进程并没有加快速度。

如果花时间查询 PyPI 和查找包(特别是当您还从 Github 和其他来源下载时),那么设置自己的 PyPI 可能会有所帮助。您可以自己托管 PyPI 并将以下内容添加到您的requirements.txt文件 ( docs ):

--extra-index-url YOUR_URL_HERE

或者如果您希望完全替换官方 PyPI,请使用以下内容:

--index-url YOUR_URL_HERE

这可能会加快下载时间,因为现在可以在附近的机器上找到所有包。

很多时间也花在用 C 代码编译包上,比如 PIL。如果这被证明是瓶颈,那么值得研究在多个进程中编译代码。您甚至可以在您的机器之间共享已编译的二进制文件(但许多事情需要相似,例如操作系统、CPU 字长等)

于 2012-06-13T18:43:37.693 回答
3

如果您让构建系统(例如 Jenkins)构建并将所有内容安装到特定于构建的虚拟环境目录中,它会有所帮助吗?构建成功后,您使虚拟环境可重定位,将其打包并将生成的 tablall 推送到您的“released-tarballs”存储中。在部署时,您需要获取最新的 tarball 并将其解压缩到目标主机上,然后它应该可以执行了。因此,如果下载 tarball 需要 2 秒,在目标主机上解压需要 0.5 秒,那么您的部署将需要 2.5 秒。

这种方法的优点是所有包安装都发生在构建时,而不是部署时。

警告:构建/编译/安装东西到虚拟环境中的构建系统工作人员必须使用与目标硬件相同的架构。此外,您的生产盒配置系统将需要处理某些 Python 包可能具有的各种 C 库依赖项(例如,在编译 JPEG 相关代码之前PIL需要安装它,如果目标盒上没有安装libjpeg,事情也会中断)libjpeg

它对我们很有效。

使虚拟环境可重定位:

virtualenv --relocatable /build/output/dir/build-1123423

在此示例build-1123423中是特定于构建的虚拟 env 目录。

于 2012-06-13T19:36:11.433 回答
0

我遇到了类似的问题,最终得到以下结果:

cat requirements.txt | sed -e '/^\s*#.*$/d' -e '/^\s*$/d' | xargs -n 1 python -m pip install

这将逐行读取 requirements.txt 并执行 pip。我无法从哪里找到正确的答案,因此对此深表歉意,但我在下面找到了一些理由:

  1. sed 的工作原理:https ://howto.lintel.in/truncate-empty-lines-using-sed/
  2. 另一个类似的答案,但使用 git:https ://stackoverflow.com/a/46494462/7127519

希望这有助于替代方案。我在这里发布了这个解决方案https://stackoverflow.com/a/63534476/7127519,所以也许那里有一些帮助。

于 2020-08-22T09:10:43.207 回答
0

手头的答案是使用例如诗歌,如果可以的话,默认情况下并行下载/安装。但问题是关于点子的,所以:

如果你们中的一些人需要安装requirements.txt具有hash参数和 python 说明符(或只是散列)的依赖项,则不能正常使用pip install,因为它不支持它。您唯一的选择是使用pip install -r

所以问题是如何从每个依赖项都定义了哈希和 python 说明符的需求文件中并行安装?这里是需求文件的外观:

swagger-ui-bundle==0.0.9; python_version >= "3.8" and python_version < "4.0" \
    --hash=sha256:cea116ed81147c345001027325c1ddc9ca78c1ee7319935c3c75d3669279d575 \
    --hash=sha256:b462aa1460261796ab78fd4663961a7f6f347ce01760f1303bbbdf630f11f516
typing-extensions==4.0.1; python_version >= "3.8" and python_version < "4.0" \
    --hash=sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b \
    --hash=sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e
unicon.plugins==21.12; python_version >= "3.8" and python_version < "4.0" \
    --hash=sha256:07f21f36155ee0ae9040d810065f27b43526185df80d3cc4e3ede597da0a1c72

这是我带来的:

# create temp directory where we store split requirements
mkdir -p pip_install
# join lines that are separated with `\` and split each line into separate 
# requirements file (one dependency == one file),
# and save files in previously created temp directory
sed ':x; /\\$/ { N; s/\\\n//; tx }' requirements.txt | split -l 1 - pip_install/x
# collect all file paths from temp directory and pipe them to xargs and pip
find pip_install -type f | xargs -t -L 1 -P$(nproc) /usr/bin/python3 -mpip install -r
# remove temp dir
rm -rf pip_install
于 2022-01-18T16:03:33.730 回答
-4

Jamieson Becker 的回答启发,我修改了一个安装脚本来进行并行 pip 安装,这似乎是一种改进。我的 bash 脚本现在包含这样的片段:

requirements=''\
'numpy '\
'scipy '\
'Pillow '\
'feedgenerator '\
'jinja2 '\
'docutils '\
'argparse '\
'pygments '\
'Typogrify '\
'Markdown '\
'jsonschema '\
'pyzmq '\
'terminado '\
'pandas '\
'spyder '\
'matplotlib '\
'statlab '\
'ipython[all]>=3 '\
'ipdb '\
''tornado>=4' '\
'simplepam '\
'sqlalchemy '\
'requests '\
'Flask '\
'autopep8 '\
'python-dateutil '\
'pylibmc '\
'newrelic '\
'markdown '\
'elasticsearch '\
"'"'docker-py==1.1.0'"'"' '\
"'"'pycurl==7.19.5'"'"' '\
"'"'futures==2.2.0'"'"' '\
"'"'pytz==2014.7'"'"' '

echo requirements=${requirements}
for i in ${requirements}; do ( pip install $i > /tmp/$i.out 2>&1 & ); done

我至少可以手动查找问题。

于 2015-05-24T20:02:35.973 回答