<p>a instalação pip de um diretório é muito lenta</p>

Criado em 16 dez. 2014  ·  74Comentários  ·  Fonte: pypa/pip

Consulte https://github.com/pypa/pip/issues/2195#issuecomment -524606986 para obter um resumo desse problema.


Não sei por que o pip precisa de 17 segundos para processar um diretório local que não está no NFS (na verdade, está em uma unidade SSD) para o pip, que não tem dependências, já que tudo é vendido.

$ 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

Provavelmente, ele deveria estar registrando o que quer que esteja demorando tanto, mas talvez nem devesse estar fazendo o que está fazendo.

Observe que a linha "Processando" aparece imediatamente e quase todo o atraso parece estar entre essa linha e a próxima.

needs discussion enhancement

Comentários muito úteis

A implementação do PEP 517 resolverá isso.

Narrador: não o fez.

Todos 74 comentários

Ele está fazendo uma cópia de todo o diretório, incluindo .git . Provavelmente não deveria estar fazendo isso, não.

$ 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

Eu tentei passar 3 -v 's ( time pip install -vvv --no-install ~/dev/git-repos/pip ) - que não rendeu mais nenhuma informação.

Percorrendo tudo com pdb, as coisas ficam mais lentas quando eu chego a:

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

E sim, @tomprince está certo - fica mais lento quando faz uma cópia de toda a árvore:

> /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

É muito mais rápido agora que https://github.com/pypa/pip/pull/2196 foi mesclado.

Deve ser reaberto visto que # 2196 foi revertido. Eu gostaria de vir com um PR alternativo que constrói um sdist em vez de usar heurísticas para descobrir o que copiar. Veja os comentários sobre esse PR para obter detalhes.

$ 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

Caramba, quase 3 minutos.

Provavelmente devido a isto:

$ du -sh .tox
177M    .tox

O diretório .tox tem 177 milhões de um total de 270 milhões para todo o meu diretório pip .

Consulte https://github.com/pypa/pip/pull/2535 , que acelera unpack_file_url criando um sdist e descompactando-o.

Este problema deve ser reaberto, porque o PR mesclado não fez nada (consulte gh-3219).

Algum progresso para este problema?

Não, e não parece que a solução final chegará tão cedo. O PEP 516 ou o PEP 517 precisam ser aceitos antes que uma decisão possa ser tomada sobre se gerar sdist primeiro é correto (eu pessoalmente não acho).

PEP 516 resume-o como:

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.

Provavelmente, o mais fácil é alguém enviar um PR mais simples que corrige o comportamento mais estúpido, como copiar tudo de .git e .tox (supondo que isso ainda aconteça hoje). Isso seria uma aceleração significativa em muitos casos e seria incontroverso.

De alguma forma, problema semelhante ao que fazer ao instalar a partir do repositório vazio (em vez da distribuição fonte ou devo dizer pacote publicado) no npm - execute prepublish para pacotes de url git

@rgommers Que tal adicionar um arquivo .pipignore para listar arquivos e diretórios a serem ignorados como .gitignore vez de codificar alguns nomes de arquivo / diretório como .git e .tox ?

Essa não é uma boa ideia - ela transfere a responsabilidade de lidar com essa lentidão para o desenvolvedor de cada pacote, o que simplesmente não funciona.

Se o npm tiver, deve ser bom :) - https://docs.npmjs.com/misc/developers#keeping -files-out-of-your-package

isso também quebra ativamente coisas como setuptools_scm ainda mais ^^ - pip install fazer uma cópia de pasta já quebra as coisas

O que setuptools_scm tem a ver com isso? Ele deve ser executado em um repositório válido e não em qualquer tipo de pacote de

Essa não é uma boa ideia - ela transfere a responsabilidade de lidar com essa lentidão para o desenvolvedor de cada pacote, o que simplesmente não funciona.

Faça com que .pipignore inclua implicitamente .git, .hg etc. com .pipignore vazio suprimindo isso.

@ piotr-dobrogost uma instalação de pip de um repositório de origem será interrompida em várias circunstâncias em que o pip não copie contexto suficiente - por exemplo, pypa / setuptools_scm # 138

Anteriormente , ignorávamos diretórios como .git e outros e quebramos coisas como pbr e tivemos que reverter a alteração.

@dstufft ainda quebra coisas se alguém estiver em um subdiretório de um repositório git em vez do root ^^

Hmm, se essa quebra foi ruim o suficiente, então não há maneira simples de melhorar as coisas aqui. Acho que está esperando por um dos PEPs de construção então.

pbr deve estar fazendo algo irracional se cair sem um .git dir presente, mas bem ....

está se perguntando se há algum progresso nisso? além de .git ou qualquer pasta .${scm} problemática, é muito pior se as pessoas incluírem .vagrant/ junto com a fonte.

ter um .pipignore personalizável realmente ajudaria a aliviar a dor.

Para outro ponto de dados; temos uma mistura de Python e Javascript em alguns projetos, pois usamos o Sphinx para documentar nossos projetos Javascript. Portanto, o pip também está copiando um diretório node_modules muito grande, que pode ser dolorosamente lento.

Portanto, votaríamos na opção .pipignore pois nosso caso de uso destaca que os valores codificados não serão necessariamente suficientes para todos os tipos de projetos.

As pessoas mantêm todos os tipos de lixo na árvore, além do arquivo SCM.

Tenho algumas simulações grandes (16GB +) produzidas pelo código que mantenho no mesmo diretório com o código-fonte do pacote (como forma de acompanhar diferentes projetos).

pip install . copia-os para o meu / tmp. A partição pobre realmente fica sem espaço e o pip falha com um erro de espaço em disco.

Se sdist não deve ser usado e .pipignore expande a interface, que tal reutilizar o código para analisar o arquivo MANIFEST.in / MANIFEST? Deve ter descrito todos os arquivos necessários para a instalação.

Uma boa solução parece ser usar uma instalação editável ( pip install -e $DIR ).

Uma boa solução alternativa parece ser usar uma instalação editável (pip install -e $ DIR).

Exceto, para teste, que não testa o que um usuário instalando o pacote de pypi usaria. (por exemplo, pacotes e módulos que não são empacotados ainda estarão disponíveis)

Espero que isso tenha sido mencionado antes neste tópico.

Uma solução alternativa melhor seria construir um sdist ou uma roda diretamente usando setup.py e instalar o artefato gerado usando pip. Dessa forma, o pip não fará a cópia do diretório (porque tem um arquivo para instalar) e este é exatamente o mesmo resultado que você faria com pip install . (a partir do pip 9), menos o cópia do diretório.

Pelo amor de Deus, pessoal, isso já pode ser resolvido de alguma forma, por favor? Quer dizer, parece haver algum consenso de que esse comportamento é estúpido - mas o ticket está aberto há três anos agora, e não há solução à vista. Eu odeio ter que mover dados manualmente para dentro e para fora da minha árvore apenas para que o pip não vomite ou fique pendurado por alguns minutos (eu tenho que trabalhar em sistemas de arquivos compartilhados).

Se não houver consenso sobre como não interromper o trabalho existente, uma solução como .pipignore ser fornecida como um opt-in, talvez? Eu não me importo de pular alguns obstáculos para consertar isso.

@ andre-merzky, por favor, acalme-se.

Estamos cientes do problema, mas somos uma organização voluntária com recursos muito limitados. E, em termos práticos, esse problema simplesmente não afeta o suficiente de nossos usuários de forma severa o suficiente para estar no topo da lista de prioridades.

Isso será corrigido no devido tempo (e o trabalho mais importante que estamos tentando resolver no momento, especificamente o PEP 517, provavelmente resolverá esse problema como um efeito colateral), mas gritar com os voluntários não ajudará. Se você sentir que uma correção imediata é crítica, ficaríamos felizes em revisar um PR - mas você deve estar ciente de que mesmo se você levantar um PR e conseguir que ele seja aceito, ele não será lançado até o PIP 10, e isso é o lançamento que gostaríamos de obter pelo menos parte do trabalho "importante" que mencionei acima (pode não acontecer devido a restrições de recursos voluntários novamente, mas esse é o nosso objetivo). Portanto, ele pode ser substituído antes de ser lançado - mas isso não significa que você não seja bem-vindo para criar um PR, será um retrocesso caso os planos maiores não cheguem a tempo.

@pfmoore desculpe pelo tom, a frustração estava falando ... Eu criei um PR para uma correção trivial (e, portanto, possivelmente inaceitável) (# 4900). Eu ouvi você sobre o ciclo de lançamento, é assim que as coisas acontecem, eu sei ...

Também encontrei isso:

(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

Após a reinicialização:

(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

Onde está o relatório de criação de perfil mais recente sobre o problema?

Sem alterações aqui. Hoje, o pip ainda está copiando o pacote inteiro para um diretório de construção temporário.

Este diretório está na memória?

Não, é gravado no disco - o que o torna particularmente difícil em sistemas de arquivos compartilhados ...

É pelo menos em /tmp ou /dev/shm ? https://stackoverflow.com/questions/9745281/tmp-vs-dev-shm-for-temp-file-storage-on-linux Ele pode detectar quando tmpfs não é usado e propor a criação de um?

Ele está em /tmp . Depende do stdlib tempfile .

A implementação do PEP 517 resolverá isso.

Estou tendo isso com a versão de desenvolvedor mais recente do pip - pensei que o suporte PEP 517 foi adicionado no pip 19, então isso ainda deveria estar acontecendo?

No meu caso, como trabalho em um projeto (astropy) no qual tenho muitos remotos e branches, meu diretório .git é de 1,8 GB e leva minutos para copiá-lo para um diretório temporário. Parece que faria mais sentido construir uma distribuição de código-fonte primeiro e, em seguida, construir a roda a partir daí, nos bastidores.

Ainda estamos sofrendo muito por causa desse problema também. É realmente difícil dizer aos nossos usuários que eles não podem manter o código e os dados experimentais (que são grandes) no mesmo diretório - é um pouco contra-intuitivo. Em nossos próprios sistemas, usamos o patch .pipignore , mas não temos a capacidade de implantá-lo na maioria dos sistemas aos quais oferecemos suporte ...: /

Encontramos este https://github.com/pypa/pip/issues/2195#issuecomment -351258913 hoje também. Ainda está acontecendo.

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

A implementação do PEP 517 resolverá isso.

Narrador: não o fez.

Corrigir isso requer a instalação via sdist e, da última vez que discutimos isso, houve muitas resistências de pessoas que usam ferramentas que (aparentemente) precisam do diretório de origem real. Pessoalmente, acho que devemos morder a bala e descontinuar os processos de compilação que não dão os mesmos resultados quando você faz build_sdist depois build_wheel como você obtém quando faz build_wheel , mas não tenho tempo ou energia para defender essa proposta sozinho no momento.

Corrigir isso requer a instalação via sdist

Na verdade, não - # 4900 forneceu uma implementação que resolve o problema com pouco código de uma forma compatível com versões anteriores. Pode não resolver outros problemas - mas dada a idade deste tíquete, gostaria de pedir para reconsiderar essa abordagem.

Corrigir isso requer a instalação via sdist e, da última vez que discutimos isso, houve muitas resistências de pessoas que usam ferramentas que (aparentemente) precisam do diretório de origem real. Pessoalmente, acho que devemos morder a bala e descontinuar os processos de compilação que não dão os mesmos resultados quando você faz build_sdist e depois build_wheel que você obtém quando você apenas faz build_wheel, mas eu não tenho tempo ou energia para defender essa proposta sozinho no momento.

Como alguém que se preocupava com a construção local e, portanto, não gostava do "deve sempre seguir a rota sdist": há muito tempo fiz as pazes com a "rota sdist".

Este problema é _muito_ doloroso se você se deparar com ele, e "copiar tudo por padrão" faz pouco sentido. Então +10 para morder a bala.

Corrigir isso requer a instalação via sdist

Eu tinha, incorretamente, assumido que faríamos a troca com o PEP 517.

Eu concordo totalmente com você aqui.

Poderíamos ter feito o IIRC, mas os debates que teria desencadeado sobre se a instalação via sdist era aceitável eram muito mais controvérsias para adicionar na época - e como instalar via cópia e construir uma roda ainda era uma opção, aceitei o menos estressante curso :-)

Eu ainda prefiro mudar para a construção via sdist, mas não tenho tempo agora para fazer isso sozinho.

solução alternativa: use um clone raso (mude a profundidade para se adequar):

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

Para reiterar e resumir:

  • Os mantenedores do pip concordam que esta não é uma boa experiência para os usuários. Os próprios processos de desenvolvimento do pip atingiram esse problema.
  • A razão disso acontecer é que o pip copia o diretório de origem para um diretório temporário, para garantir que a construção não dependa de algo fora do código-fonte.
  • A maneira como queremos resolver esse problema é mudar o comportamento do pip para construir uma distribuição de código-fonte na árvore, descompactar a distribuição de código-fonte em um diretório temporário e construir um binário a partir dele.

Agora, seguir esse caminho também corrige um monte de outros problemas de usabilidade em torno da mecânica de construção do pip para os usuários.

Comecei um projeto automotivado para refatorar a lógica de construção do pip. Embora eu não vá abordar esse problema como parte do meu trabalho de refatoração, estou mais do que disposto a ajudar alguém que está inclinado o suficiente para tentar corrigir esse problema - a correção estaria bastante envolvida na lógica de construção do pip, que não não é o trecho de código mais direto e pode haver casos extremos complicados que apenas notamos durante a implementação.

Ah, e como uma solução alternativa para isso, adicionado em # 6770, o pip 19.3 excluirá os diretórios .nox e .tox ao copiar. Isso deve reduzir a quantidade de tempo que essas instalações levariam, para um número razoável de usuários.

Isso não resolve o problema para diretórios .git ou build - isso é o que resolveria a abordagem que elaborei no meu comentário acima. :)

Isso não resolve o problema de grandes diretórios .git ou build - isso é o que resolveria a abordagem que elaborei em meu comentário acima. :)

Eu sei que existem algumas ferramentas que dependem de .git , mas alguém está contando com build sendo copiado? Isso seria bom para adicionar aos dirs ignorados, feliz em enviar um PR se você concordar.

Isso ainda está sendo investigado? É uma surpresa muito dolorosa ver vários gigabytes de despejos de dados de depuração ignorados por git sendo copiados durante um pip install .

Sim, dê uma olhada nos problemas vinculados, como # 7555.

Esse problema ainda persiste, porque o diretório de onde estou instalando tem talvez 10 MB de código python, mas muitos arquivos de dados json e .git .

Isso deve ser resolvido por # 7882 (crie diretórios locais no local).

Agora (de acordo com o nº 7951) publicamos uma versão beta do pip, pip 20.1b1. Esta versão inclui o nº 7882, que implementou uma solução para esse problema.

Espero que os participantes desta edição nos ajudem testando o beta e verificando se há novos bugs. Gostaríamos de identificar e resolver quaisquer problemas em potencial antes do lançamento principal do 20.1 na terça-feira.

Também agradeço o feedback positivo do tipo "sim, funciona melhor agora!" também, uma vez que o rastreador de problemas geralmente está cheio de "problemas". :)

Direi que é consideravelmente melhor.

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

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

Funciona muito bem / mais rápido para mim! : +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

de ~ 2 minutos para 4 segundos, muito obrigado!

Obrigado pelos relatórios positivos @PythonCoderAS @astrofrog @klamann! :)

Infelizmente, houve uma série de problemas com a implementação de compilações no local (que estão sendo rastreados sob o número 7555), o que significa que, por enquanto, precisamos reverter o número 7882. Como resultado, esse problema se tornará um problema novamente e, portanto, iremos reabri-lo. A longo prazo, esperamos ter uma solução que aborde os problemas que as compilações in-loco resolveram, mas sem o impacto em outros fluxos de trabalho que a solução atual teve.

Desculpe pela interrupção que isso irá causar.

Infelizmente, houve uma série de problemas com a implementação de compilações in-loco

@pradyunsg obrigado pela atualização. Algum feedback sobre a terminologia (sinta-se à vontade para ignorar, apenas para sua informação): esta frase, assim como gh-7555, me confundiu porque o pip não faz compilações no local. O que as compilações no local sempre significaram é python setup.py build_ext --inplace (ou python setup.py develop ).

Aqui você mudou o significado para: "build without copying to a tmpdir". Módulos de extensão ainda não acabam no lugar, eles acabam em um diretório build/ que geralmente é facilmente limpo. Seria bom ser um pouco mais explícito, por exemplo, gh-7555.

Essa foi originalmente a minha formulação. Desculpe qualquer confusão, eu não sabia que setuptools usava o termo "no lugar" para significar algo diferente (e ainda não tenho certeza de como essa terminologia se aplica fora de setuptools). Veremos se podemos encontrar um termo mais neutro no futuro (embora de improviso, não tenho certeza do que - sugestões aceitas com gratidão 😉)

Não se preocupe, obrigado @pfmoore. Eu apenas pensei em apontar isso, já que confusão sobre a terminologia às vezes pode resultar em conversas.

e ainda não tenho certeza de como essa terminologia se aplica fora das ferramentas de configuração

Para ferramentas como CMake e scikit-build, acho que significa a mesma coisa: na verdade, no local, os binários pousam próximos às fontes.

"instalações editáveis", por outro lado, é (eu acredito) inventado aqui, e meio que significa "no local que o pip está ciente".

embora improvisamente, não tenho certeza do que - sugestões aceitas com gratidão

talvez apenas "compilação local" (vs. a "cópia para tmpdir e compilação" atual)?

"instalações editáveis", por outro lado, é (eu acredito) inventado aqui, e meio que significa "no local que o pip está ciente".

Recentemente, tivemos uma longa discussão sobre o que significa instalação editável e acho que realmente pousamos em um lugar que é mais parecido com machine local que diz respeito ao pip. Mas pip não tem conhecimento de onde e como na máquina local e é o trabalho de construção de back-ends para definir e lidar com isso.

Pode tentar «compilar na árvore» (semelhante a «infra-estrutura PEP 517 na árvore») ou «compilar no diretório de origem»

Minha pergunta é: por que o recurso não pode ser opcional, para que não cause problemas, mas pode ser ativado por um argumento ou algo semelhante?

Estou tentando entender as soluções alternativas para isso, onde uma instalação editável não é uma opção. Existe algum?

Uma solução alternativa poderia ser construir uma roda (usando seu back-end de construção diretamente) e apontar pip para instalá-la

por que o recurso não pode ser opcional, para não causar problemas, mas pode ser ativado por um argumento ou algo semelhante?

Pode. O motivo para reverter a mudança foi que não tínhamos opt-out ou um período para obter feedback sobre a mudança. Temos novos sinalizadores para ajudar a facilitar isso (--use-feature e --deprecated-feature), mas alguém precisa reimplementar / reintroduzir a funcionalidade neste contexto agora.

Em termos gerais, acho que o que queremos fazer aqui é:

  • Adicione um --use-feature = in-tree-build como opção.
  • Mude o padrão em uma versão posterior com --deprecated-feature = out-of-tree-build como um opt-out + empurrando os usuários de --use-feature = in-tree-build para removê-lo.
  • Abandone ambas as opções em uma versão subsequente.

Uma solução alternativa poderia ser construir uma roda (usando seu back-end de construção diretamente) e apontar pip para instalá-la

Eu estava pensando sem uma etapa de construção extra. Mas eu acho que nunca deveria ter pensado que Python poderia escapar sem equivalentes Makefile desde o início.

Esta página foi útil?
0 / 5 - 0 avaliações