<p>目录的 pip 安装非常慢</p>

创建于 2014-12-16  ·  74评论  ·  资料来源: pypa/pip

有关此问题的摘要,请参阅https://github.com/pypa/pip/issues/2195#issuecomment -524606986。


我怀疑为什么 pip 需要 17 秒来处理 pip 不在 NFS 上的本地目录(实际上,它在 SSD 驱动器上),因为 pip 没有依赖关系,因为一切都是供应商提供的。

$ time pip install --no-install ~/dev/git-repos/pip
DEPRECATION: --no-install and --no-download are deprecated. See https://github.com/pypa/pip/issues/906.
Processing /Users/marca/dev/git-repos/pip
  Requirement already satisfied (use --upgrade to upgrade): pip==6.0.dev1 from file:///Users/marca/dev/git-repos/pip in /Users/marca/dev/git-repos/pip
pip install --no-install ~/dev/git-repos/pip  2.80s user 5.86s system 50% cpu 17.205 total

它可能至少应该记录花费那么长时间的任何事情,但也许它甚至不应该做任何它正在做的事情。

请注意,“处理”行立即出现,几乎整个延迟似乎都在该行和下一行之间。

needs discussion enhancement

最有用的评论

实施 PEP 517 将解决这个问题。

旁白:没有。

所有74条评论

它正在制作整个目录的副本,包括.git 。 它可能不应该这样做,不。

$ du -sh pip
263M    pip
$ du -sk * .cache .git .tox .travis | sort -nr | head -n 5
181860  .tox
34836   tests
31700   .git
9212    pip
2852    build

我尝试传递 3 -v 's ( time pip install -vvv --no-install ~/dev/git-repos/pip ) - 没有产生更多信息。

使用 pdb 逐步完成,当我到达时,事情会变慢:

> /Users/marca/dev/git-repos/pip/pip/req/req_set.py(365)prepare_files()
-> unpack_url(

是的, @tomprince是对的 - 当它复制整个树时它会变慢:

> /Users/marca/dev/git-repos/pip/pip/download.py(635)unpack_file_url()
-> shutil.copytree(link_path, location, symlinks=True)
$ time pip install --no-install ~/dev/git-repos/pip
DEPRECATION: --no-install and --no-download are deprecated. See https://github.com/pypa/pip/issues/906.
Processing /Users/marca/dev/git-repos/pip
  2014-12-15 15:23:34.630794: Copying tree; link_path = '/Users/marca/dev/git-repos/pip'; location = '/var/folders/gw/w0clrs515zx9x_55zgtpv4mm0000gp/T/pip-D6etc4-build'
  2014-12-15 15:23:57.418679: DONE copying tree; link_path = '/Users/marca/dev/git-repos/pip'; location = '/var/folders/gw/w0clrs515zx9x_55zgtpv4mm0000gp/T/pip-D6etc4-build'
  Requirement already satisfied (use --upgrade to upgrade): pip==6.0.dev1 from file:///Users/marca/dev/git-repos/pip in /Users/marca/dev/git-repos/pip
pip install --no-install ~/dev/git-repos/pip  2.75s user 5.03s system 32% cpu 24.168 total
>>> elapsed time 24s

现在https://github.com/pypa/pip/pull/2196合并了,速度要快得多。

这应该重新打开,因为 #2196 已恢复。 我想提供一个替代 PR 来构建一个 sdist 而不是使用启发式来找出要复制的内容。 有关详细信息,请参阅对该 PR 的评论。

$ time pip install --no-install ~/dev/git-repos/pip
DEPRECATION: --no-install and --no-download are deprecated. See https://github.com/pypa/pip/issues/906.
Processing /Users/marca/dev/git-repos/pip
  Requirement already satisfied (use --upgrade to upgrade): pip==6.1.0.dev0 from file:///Users/marca/dev/git-repos/pip in /Users/marca/dev/git-repos/pip
pip install --no-install ~/dev/git-repos/pip  3.67s user 8.12s system 7% cpu 2:45.83 total
>>> elapsed time 2m46s

哎呀,快3分钟了。

大概是因为这个:

$ du -sh .tox
177M    .tox

.tox目录是我整个pip目录总共 270M 中的 177M。

请参阅https://github.com/pypa/pip/pull/2535 ,它通过构建 sdist 并解包来加速unpack_file_url

这个问题应该重新打开,因为合并的 PR 什么也没做(参见 gh-3219)。

这个问题有什么进展吗?

不,而且看起来最终解决方案不会很快到来。 PEP 516 或 PEP 517 需要接受才能决定首先生成sdist是否正确(我个人不这么认为)。

PEP 516 将其总结为:

Being able to create new sdists from existing source trees isn't a thing pip does today,
and while there is a PR to do that as part of building from source, it is contentious and
lacks consensus.

可能最简单的方法是让某人提交一个更简单的 PR 来修复最愚蠢的行为,比如复制所有的.git.tox (假设今天仍然发生)。 在许多情况下,这将是一个显着的加速,并且没有争议。

在 npm 中从裸仓库(而不是源代码分发,或者我应该说已发布的包)安装时要做什么类似的问题 -为 git url 包运行prepublish

@rgommers如何添加一个文件.pipignore来列出要忽略的文件和目录,如.gitignore而不是硬编码某些文件/目录名称,如.git.tox ?

这不是一个好主意 - 它将处理这种缓慢的责任转移到每个包的开发人员身上,这就是行不通的。

如果 npm 有它一定很好:) – https://docs.npmjs.com/misc/developers#keeping -files-out-of-your-package

这也积极地破坏了 setuptools_scm 之类的东西 ^^ - pip install 制作文件夹副本已经很困难了

setuptools_scm 与它有什么关系? 它应该在有效的 repo 上运行,而不是任何类型的源包

这不是一个好主意 - 它将处理这种缓慢的责任转移到每个包的开发人员身上,这就是行不通的。

让 .pipignore 隐含地包含 .git、.hg 等,而空的 .pipignore 会抑制这个。

@piotr-dobrogost 从源代码库安装 pip 会在 pip 没有复制足够上下文的各种情况下中断 - 例如 pypa/setuptools_scm#138

我们之前确实忽略了像.git类的目录,并且破坏了 pbr 之类的东西,不得不恢复更改。

@dstufft如果它位于 git repo 的

嗯,如果破损已经够严重了,那么这里就没有简单的方法可以改进了。 猜猜它正在等待其中一个构建 PEP。

如果 pbr 在没有.git目录的情况下摔倒了,它一定是在做一些非常不合理的事情,但是......

想知道这方面是否有任何进展? 不仅.git或任何.${scm}文件夹很麻烦,如果人们将.vagrant/与源一起包含在内,情况会更糟。

拥有一个可定制的.pipignore真的有助于减轻痛苦。

对于另一个数据点; 我们在一些项目中混合使用了 Python 和 Javascript,因为我们使用 Sphinx 来记录我们的 Javascript 项目。 因此,pip 也在复制一个非常大的node_modules目录,这可能会非常缓慢。

因此,我们将投票支持.pipignore选项,因为我们的用例强调硬编码值不一定适用于所有类型的项目。

人们确实在 SCM 文件之外的树中保留了各种垃圾。

我有一些由我与包源代码保存在同一目录中的代码生成的大型模拟(16GB +)(作为跟踪不同项目的一种方式)。

pip install .它们复制到我的 /tmp。 糟糕的分区实际上用完了空间并且 pip 因磁盘空间错误而失败。

如果不应该使用sdist,并且.pipignore扩展了接口,那么重用解析MANIFEST.in/MANIFEST文件的代码呢? 它应该描述了安装所需的所有文件。

一个好的解决方法似乎是使用可编辑的安装 ( pip install -e $DIR )。

一个好的解决方法似乎是使用可编辑的安装(pip install -e $DIR)。

除了测试之外,这不会测试用户从 pypi 安装软件包将使用什么。 (例如,未打包的包和模块仍然可用)

我希望这在这个线程之前已经提到过。

更好的解决方法是直接使用 setup.py 构建 sdist 或轮子,并使用 pip 安装生成的工件。 这样,pip 就不会执行目录复制操作(因为它有一个要安装的文件),这与使用pip install . (从 pip 9 开始)完全相同的结果,减去目录复制。

看在上帝的份上,伙计们,这可以以某种方式解决吗? 我的意思是,似乎有一些共识认为这种行为是脑残 - 但现在票已经开放三年了,而且看不到解决方案。 我讨厌必须手动将数据移入和移出我的树,这样 pip 就不会停止或挂起几分钟(我必须在共享文件系统上工作)。

如果没有就如何不破坏现有工作达成共识,是否可以提供像.pipignore这样的解决方案作为选择加入? 我不介意跳过一些箍来解决这个问题。

@andre-merzky 请冷静。

我们知道这个问题,但我们是一个资源非常有限的志愿者组织。 实际上,这个问题对我们的用户影响不够严重,不足以排在优先级列表的前列。

它会在适当的时候得到修复(我们目前正在努力解决的更重要的工作,特别是 PEP 517,可能会作为副作用解决这个问题),但对志愿者大喊大叫无济于事。 如果您认为立即修复很重要,我们很乐意审核 PR - 但您应该意识到,即使您确实提出了 PR 并被接受,它也不会在 PIP 10 之前发布,那就是我们希望至少获得一些我上面提到的“大票”工作的发布(由于志愿者资源的限制,它可能不会再次发生,但这是我们的目标)。 所以它可能会在发布之前被取代——但这并不意味着你不欢迎创建 PR,如果更大的计划没有及时实现,这将是一个后备。

@pfmoore对语气感到抱歉,说的是沮丧......我为一个微不足道的(因此可能是不可接受的)修复创建了一个 PR (#4900)。 我听说你在发布周期,事情就是这样,我知道......

也遇到了这个:

(env) $ find node_modules/ | wc -l
140287
(env) $ time pip install .
Processing /path/to/myproject
Installing collected packages: myproject
  Running setup.py install for myproject ... done
Successfully installed myproject-1.0

real    4m35.598s
user    0m6.928s
sys 0m7.992s

重置后:

(env) $ mv node_modules/ ../
(env) $ time pip install .
Processing /path/to/myproject
Installing collected packages: myproject
  Running setup.py install for myproject ... done
Successfully installed myproject-1.0

real    0m0.899s
user    0m0.496s
sys 0m0.120s

有关该问题的最新分析报告在哪里?

这里没有变化。 今天,pip 仍在将整个包复制到临时构建目录。

这个目录在内存中吗?

不,它写入磁盘 - 这使得它在共享文件系统上特别痛苦......

至少在/tmp/dev/shm吗? https://stackoverflow.com/questions/9745281/tmp-vs-dev-shm-for-temp-file-storage-on-linux它可以检测到何时没有使用tmpfs并建议创建一个吗?

它在/tmp 。 这取决于标准库tempfile

实施 PEP 517 将解决这个问题。

我在使用最新的 pip 开发人员版本时遇到了这个问题 - 我认为 PEP 517 支持已添加到 pip 19 中,所以这仍然会发生吗?

就我而言,因为我在一个项目 (astropy) 上工作,其中有许多遥控器和分支,所以我的 .git 目录是 1.8Gb,将它复制到临时目录需要几分钟。 似乎首先构建源代码分发然后在幕后从那里构建轮子更有意义。

由于这个问题,我们仍然受到很大的伤害。 很难告诉我们的用户他们不能将代码和实验数据(很大)保存在同一目录中 - 这非常违反直觉。 在我们自己的系统上,我们使用.pipignore补丁,但无法在我们支持的大多数系统上部署它...:/

我们今天也遇到了这个https://github.com/pypa/pip/issues/2195#issuecomment -351258913。 它仍在发生。

(venv) (venv) pip --version
pip 19.1.1 from /application/venv/lib/python2.7/site-packages/pip (python 2.7)

实施 PEP 517 将解决这个问题。

旁白:没有。

解决这个问题需要通过 sdist 进行安装,上次我们讨论过这个问题时,使用工具(显然)需要实际源目录的人有很多反对意见。 我个人认为,我们应该咬紧牙关,不建议使用的构建过程,当你这样做不给相同的结果build_sdist然后build_wheel为你当你只是做build_wheel ,但我目前没有时间或精力支持这个提议。

解决这个问题需要通过 sdist 安装

实际上,没有 - #4900 提供了一个实现,它以向后兼容的方式用很少的代码解决了这个问题。 它可能无法解决其他问题 - 但鉴于这张票的年龄,我想要求重新考虑这种方法。

解决这个问题需要通过 sdist 进行安装,上次我们讨论过这个问题时,使用工具(显然)需要实际源目录的人有很多反对意见。 就我个人而言,我认为我们应该咬紧牙关并弃用在执行 build_sdist 和 build_wheel 时不会产生与执行 build_wheel 时得到的结果相同的构建过程,但我没有时间或精力亲自支持该提案在这一刻。

作为关心就地构建并因此不喜欢“必须始终通过 sdist 路线”的人:我很久以前就已经接受了“走 sdist 路线”。

如果你遇到这个问题会_非常_痛苦,并且“默认复制所有内容”毫无意义。 所以+10硬着头皮。

解决这个问题需要通过 sdist 安装

我错误地认为我们会使用 PEP 517 进行转换。

不过,我完全同意你的看法。

IIRC 我们本来可以做的,但是它会引发关于通过 sdist 安装是否可以接受的辩论,当时有太多额外的争议无法添加 - 由于通过复制和构建轮子安装仍然是一种选择,我采取了压力较小的方式课程 :-)

我仍然更喜欢通过 sdist 切换到构建,但我现在没有时间自己做。

解决方法:使用浅克隆(更改深度以适应):

cd d:\code
git clone --depth=100 https://github.com/PROJECT/PROJECT.git d:/code/shallow-PROJECT
move d:\code\PROJECT d:\code\PROJECT-bloated
move d:\code\shallow-PROJECT d:\code\PROJECT

重申和总结:

  • pip 维护者同意这对用户来说不是一个好的体验。 pip 自己的开发过程遇到了这个问题。
  • 发生这种情况的原因是,pip 将源目录复制到一个临时目录,以确保构建不依赖于源外的东西。
  • 我们想要解决这个问题的方法是改变 pip 的行为以在树中构建源分发,将源分发解压缩到临时目录中并从中构建二进制文件。

现在,走这条路线还解决了围绕 pip 为用户构建机制的一系列其他可用性问题。

我已经开始了一个自我激励的项目来重构 pip 的构建逻辑。 虽然我不会将这个问题作为重构工作的一部分来解决,但我非常愿意帮助那些愿意尝试解决这个问题的人——这个修复将相当涉及 pip 的构建逻辑,这是这不是最直接的代码,可能会有我们只在实现过程中注意到的棘手的边缘情况。

哦,作为对此的创可贴解决方法,在#6770 中添加,pip 19.3 将在复制时排除.nox.tox目录。 对于相当多的用户来说,这应该会减少这些安装所需的时间。

这不能解决大型.gitbuild目录的问题——这就是我在上面的评论中阐述的方法将解决的问题。 :)

这不能解决大型.gitbuild目录的问题——这就是我在上述评论中阐述的方法将解决的问题。 :)

我知道有些工具依赖于.git ,但是有人依赖build被复制吗? 添加到忽略的目录中会很好,如果您同意,很高兴发送 PR。

这还在调查中吗? 看到在pip install .期间复制了多 GB 的 git-ignored 调试数据转储,这是一个非常痛苦的惊喜

是的,请查看链接的问题,例如 #7555。

这个问题仍然存在,因为我从中安装的目录可能有 10 mb 的 python 代码,但是有很多 json 数据文件和.git

这应该由 #7882 解决(就地构建本地目录)。

我们现在(根据 #7951)发布了 pip 的 beta 版本,pip 20.1b1。 此版本包括#7882,它为此问题实施了解决方案。

我希望这个问题的参与者通过测试 beta 和检查新的错误来帮助我们。 我们希望在周二发布 20.1 主要版本之前确定并解决所有潜在问题。

我也欢迎“是的,现在效果更好了!”的积极反馈。 同样,因为问题跟踪器通常充满了“问题”。 :)

我会说它要好得多。

旧: noglob pip3 install . 3.76s user 2.51s system 12% cpu 50.245 total

新: noglob pip3 install . 3.40s user 0.70s system 42% cpu 9.764 total

对我来说效果很好/更快! :+1:

» pip --version
pip 20.0.2 
» time pip install .
noglob pip install .  8.03s user 18.47s system 25% cpu 1:44.84 total
» pip --version
pip 20.1b1 
» time pip install .
noglob pip install .  3.69s user 0.31s system 92% cpu 4.307 total

从 2 分钟缩短到 4 秒,非常感谢!

感谢您的积极报道@PythonCoderAS @astrofrog @klamann! :)

不幸的是,就地构建的实施存在许多问题(正在#7555 下跟踪),这意味着现在,我们需要恢复#7882。 因此,这个问题将再次成为问题,因此我们将重新打开它。 从长远来看,我们希望有一个解决方案来解决就地构建解决的问题,但不会影响当前解决方案对其他工作流程的影响。

很抱歉这会造成中断。

不幸的是,就地构建的实施存在许多问题

@pradyunsg感谢您的更新。 关于术语的一些反馈(请随意忽略,仅供参考):这句话以及 gh-7555 使我感到困惑,因为 pip 不进行就地构建。 就地构建一直意味着python setup.py build_ext --inplace (或python setup.py develop )。

在这里,您将含义更改为:“无需复制到 tmpdir 即可构建”。 扩展模块仍然没有就地结束,它们最终在build/目录中,通常很容易清理。 在例如 gh-7555 中更明确一点会很好。

这原本是我的措辞。 抱歉有任何混淆,我不知道 setuptools 使用术语“就地”来表示不同的意思(我仍然不确定该术语如何应用于 setuptools 之外)。 我们会看看我们将来是否能找到一个更中性的术语(虽然是草率的,我不确定是什么 - 感激地接受建议 😉)

完全不用担心,谢谢@pfmoore。 我只是想我会指出这一点,因为术语的混淆有时会导致相互交谈。

我仍然不确定该术语如何应用于 setuptools 之外

对于像 CMake 和 scikit-build 这样的工具,我认为这意味着同样的事情:实际上就地,二进制文件位于源旁边。

另一方面,“可编辑安装”是(我相信)在这里发明的,有点意思是“pip 知道的就地”。

虽然是草率的,但我不确定是什么 - 感激地接受了建议

也许只是“本地构建”(与当前的“复制到 tmpdir 并构建”相比)?

另一方面,“可编辑安装”是(我相信)在这里发明的,有点意思是“pip 知道的就地”。

我们最近对可编辑安装的含义进行了长时间的讨论,我认为就 pip 而言,我们实际上进入了一个更接近machine local地方。 但是 pip 不知道本地机器上的位置和方式,并且是构建后端工作来定义和处理它。

可以尝试«in-tree build»(类似于«in-tree PEP 517 backend»)或«build in source dir»

我的问题是,为什么该功能不能是可选的,所以它不会引起问题,但可以通过参数或类似的东西启用?

我正在尝试解决这个问题,其中不可编辑的安装不是一个选项。 有没有?

解决方法可能是构建一个轮子(直接使用您的构建后端)然后指向 pip 安装它

为什么该功能不能是可选的,所以它不会引起问题,但可以通过参数或类似的东西启用?

它可以。 恢复更改的原因是我们没有任何选择退出或获取更改反馈的期限。 我们确实有新的标志来帮助促进这一点(--use-feature 和--deprecated-feature),但现在必须有人在这种情况下重新实现/重新引入该功能。

从广义上讲,我认为我们想要在这里做的是:

  • 添加 --use-feature=in-tree-build 作为选择加入。
  • 在以后的版本中切换默认设置,将 --deprecated-feature=out-of-tree-build 作为选择退出 + 推动 --use-feature=in-tree-build 的用户放弃它。
  • 在后续版本中删除这两个选项。

解决方法可能是构建一个轮子(直接使用您的构建后端)然后指向 pip 安装它

我在想没有额外的构建步骤。 但我想我从一开始就不应该认为 Python 可以在没有 Makefile 等价物的情况下逃脱。

此页面是否有帮助?
0 / 5 - 0 等级