<p>la instalación de pip de un directorio es muy lenta</p>

Creado en 16 dic. 2014  ·  74Comentarios  ·  Fuente: pypa/pip

Consulte https://github.com/pypa/pip/issues/2195#issuecomment -524606986 para obtener un resumen de este problema.


Dudo de por qué pip necesita 17 segundos para procesar un directorio local que no está en NFS (de hecho, está en una unidad SSD) para pip, que no tiene dependencias, ya que todo está 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

Probablemente debería al menos estar registrando lo que sea que esté tardando tanto, pero tal vez ni siquiera debería estar haciendo lo que sea que esté haciendo.

Tenga en cuenta que la línea "Procesando" aparece de inmediato y casi todo el retraso parece estar entre esa línea y la siguiente.

needs discussion enhancement

Comentario más útil

La implementación de PEP 517 solucionará este problema.

Narrador: no fue así.

Todos 74 comentarios

Está haciendo una copia de todo el directorio, incluido .git . Probablemente no debería estar haciendo eso, no.

$ 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

Intenté pasar 3 -v ( time pip install -vvv --no-install ~/dev/git-repos/pip ), que no arrojaron más información.

Pasando por él con pdb, las cosas se ralentizan cuando llego a:

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

Y sí, @tomprince tiene razón: se ralentiza cuando hace una copia de todo el árbol:

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

Es mucho más rápido ahora que se fusionó https://github.com/pypa/pip/pull/2196 .

Esto debería reabrirse ya que se revirtió el número 2196. Me gustaría venir con un PR alternativo que construya una sdist en lugar de usar heurísticas para averiguar qué copiar. Vea los comentarios sobre ese RP para más detalles.

$ 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

Vaya, casi 3 minutos.

Probablemente debido principalmente a esto:

$ du -sh .tox
177M    .tox

El directorio .tox es 177M de un total de 270M para todo mi directorio pip .

Consulte https://github.com/pypa/pip/pull/2535 , que acelera unpack_file_url al crear una sdist y desempaquetarla.

Este problema debería reabrirse, porque el RP fusionado no hizo nada (ver gh-3219).

¿Algún progreso para este problema?

No, y no parece que la solución final llegue pronto. Es necesario aceptar PEP 516 o PEP 517 antes de que se pueda tomar una decisión sobre si generar un sdist primero es correcto (personalmente no lo creo).

PEP 516 lo resume 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.

Probablemente, lo más fácil es que alguien envíe un PR más simple que corrija el comportamiento más estúpido, como copiar todo .git y .tox (asumiendo que eso todavía sucede hoy). Eso sería una aceleración significativa en muchos casos y no será controvertido.

De alguna manera, un problema similar de qué hacer al instalar desde un repositorio básico (en lugar de la distribución de origen o debería decir paquete publicado) en npm: ejecute prepublish para paquetes de URL de git

@rgommers ¿Qué tal si agregamos un archivo .pipignore a la lista de archivos y directorios que se ignorarán como .gitignore lugar de codificar algunos nombres de archivos / directorios como .git y .tox ?

Esa no es una buena idea: traslada la responsabilidad de lidiar con esta lentitud al desarrollador de cada paquete, lo que simplemente no funciona.

Si npm lo tiene, debe ser bueno :) - https://docs.npmjs.com/misc/developers#keeping -files-out-of-your-package

esto también rompe activamente cosas como setuptools_scm aún más ^^ - pip install al hacer una copia de carpeta ya rompe las cosas

¿Qué tiene que ver setuptools_scm con esto? Debe ejecutarse en un repositorio válido y no en ningún tipo de paquete fuente .

Esa no es una buena idea: traslada la responsabilidad de lidiar con esta lentitud al desarrollador de cada paquete, lo que simplemente no funciona.

Haga que .pipignore incluya implícitamente .git, .hg, etc.con .pipignore vacío suprimiendo esto.

@ piotr-dobrogost una instalación de pip desde un repositorio de origen se interrumpirá en varias circunstancias en las que pip no copia suficiente contexto, por ejemplo, pypa / setuptools_scm # 138

Previamente se hizo caso omiso de directorios como .git y tales cosas y se rompió como el PBR y tuvo que revertir el cambio.

@dstufft todavía rompe cosas si uno está en un subdirectorio de un repositorio de git en lugar de la raíz ^^

Mmmm, si esa rotura fue lo suficientemente mala, entonces no hay una manera simple de mejorar las cosas aquí. Supongo que está esperando uno de los PEP de compilación entonces.

pbr debe estar haciendo algo bastante irrazonable si se cae sin un .git dir presente, pero bueno ...

preguntándose si hay algún progreso en esto? no solo son .git o cualquier carpeta .${scm} problemática, es mucho peor si la gente incluye .vagrant/ junto con la fuente.

tener un .pipignore que sea personalizable realmente ayudaría a aliviar el dolor.

Para otro punto de datos; tenemos una mezcla de Python y Javascript en algunos proyectos, ya que usamos Sphinx para documentar nuestros proyectos de Javascript. Por lo tanto, pip también está copiando un directorio node_modules muy grande, lo que puede resultar tremendamente lento.

Por lo tanto, votaríamos por la opción .pipignore ya que nuestro caso de uso destaca que los valores codificados no serán necesariamente suficientes para todo tipo de proyectos.

La gente guarda todo tipo de basura en el árbol más allá del archivo SCM.

Tengo algunas simulaciones grandes (16GB +) producidas por el código que guardo en el mismo directorio con el código fuente del paquete (como una forma de realizar un seguimiento de los diferentes proyectos).

pip install . copia en my / tmp. La partición pobre en realidad se queda sin espacio y pip falla con un error de espacio en disco.

Si se supone que sdist no se debe usar y .pipignore expande la interfaz, ¿qué tal si se reutiliza el código para analizar el archivo MANIFEST.in / MANIFEST? Debería haber descrito todos los archivos necesarios para la instalación.

Una buena solución parece ser usar una instalación editable ( pip install -e $DIR ).

Una buena solución parece ser utilizar una instalación editable (pip install -e $ DIR).

Excepto, para la prueba, que no prueba lo que usaría un usuario que instala el paquete desde pypi. (por ejemplo, los paquetes y módulos que no se empaquetan seguirán estando disponibles)

Espero que esto se haya mencionado antes en este hilo.

Una mejor solución sería construir un sdist o una rueda directamente usando setup.py e instalar el artefacto generado usando pip. De esa manera, pip no hará las cosas de copia de directorio (porque tiene un archivo para instalar) y este es exactamente el mismo resultado que obtendría con pip install . (a partir de pip 9), menos el copia del directorio.

Por el amor de Dios, muchachos, ¿esto ya se puede resolver de alguna manera, por favor? Quiero decir, parece haber cierto consenso en que este comportamiento es una muerte cerebral; sin embargo, el boleto está abierto durante tres años y no hay una solución a la vista. Odio tener que mover manualmente los datos dentro y fuera de mi árbol solo para que pip no se eche a perder o se cuelgue durante algunos minutos (tengo que trabajar en sistemas de archivos compartidos).

Si no hay consenso sobre cómo no interrumpir el trabajo existente, ¿se puede proporcionar una solución como .pipignore como opción de suscripción, tal vez? No me importa pasar por algunos obstáculos para arreglar esto.

@ andre-merzky por favor cálmate.

Somos conscientes del problema, pero somos una organización de voluntarios con recursos muy limitados. Y en términos prácticos, este problema simplemente no afecta a un número suficiente de nuestros usuarios lo suficientemente grave como para ocupar un lugar destacado en la lista de prioridades.

Se solucionará a su debido tiempo (y es probable que el trabajo más importante que estamos tratando de abordar en este momento, específicamente PEP 517, resuelva este problema como un efecto secundario), pero gritar a los voluntarios no ayudará. Si cree que una solución inmediata es fundamental, estaremos encantados de revisar un PR, pero debe tener en cuenta que incluso si aumenta un PR y lo acepta, no se publicará hasta el PIP 10, y eso es el lanzamiento nos gustaría obtener al menos parte del trabajo "caro" al que me referí anteriormente (puede que no suceda debido a las limitaciones de recursos de los voluntarios nuevamente, pero ese es nuestro objetivo). Por lo tanto, puede ser reemplazado antes de su lanzamiento, pero eso no significa que no sea bienvenido a crear un PR, será una alternativa si los planes más grandes no se concretan a tiempo.

@pfmoore lo siento por el tono, la frustración estaba hablando ...

Me encontré con esto también:

(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

Después de reiniciar:

(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

¿Dónde está el último informe de elaboración de perfiles sobre el problema?

No hay cambios aquí. Hoy, pip sigue copiando todo el paquete en un directorio de compilación temporal.

¿Está este directorio en la memoria?

No, está escrito en el disco, lo que lo hace particularmente doloroso en los sistemas de archivos compartidos ...

¿Está al menos en /tmp o /dev/shm ? https://stackoverflow.com/questions/9745281/tmp-vs-dev-shm-for-temp-file-storage-on-linux ¿Puede detectar cuándo no se usa tmpfs y proponer crear uno?

Está en /tmp . Depende de stdlib tempfile .

La implementación de PEP 517 solucionará este problema.

Me estoy encontrando con esto con la última versión para desarrolladores de pip; pensé que se había agregado compatibilidad con PEP 517 en pip 19, así que ¿debería seguir sucediendo?

En mi caso, debido a que trabajo en un proyecto (astropy) donde tengo muchos controles remotos y sucursales, mi directorio .git es 1.8Gb, y me lleva unos minutos copiarlo en un directorio temporal. Parece que tendría más sentido construir una distribución de fuente primero y luego construir la rueda desde allí, detrás de escena.

También estamos sufriendo bastante debido a este problema. Es realmente difícil decirles a nuestros usuarios que no pueden mantener el código y los datos experimentales (que son grandes) en el mismo directorio; es bastante contrario a la intuición. En nuestros propios sistemas, usamos el parche .pipignore , pero no tenemos la capacidad de implementarlo en la mayoría de los sistemas que admitimos ...: /

También nos encontramos con este https://github.com/pypa/pip/issues/2195#issuecomment -351258913 hoy. Todavía está sucediendo.

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

La implementación de PEP 517 solucionará este problema.

Narrador: no fue así.

Arreglar esto requiere la instalación a través de sdist, y la última vez que lo discutimos, hubo una gran cantidad de rechazo por parte de las personas que usan herramientas que (aparentemente) necesitan el directorio de origen real. Personalmente, creo que deberíamos morder la bala y desaprobar los procesos de compilación que no dan los mismos resultados cuando haces build_sdist luego build_wheel como obtienes cuando solo haces build_wheel , pero no tengo el tiempo ni la energía para defender esa propuesta por mí mismo en este momento.

La solución de esto requiere la instalación a través de sdist

En realidad, no - # 4900 proporcionó una implementación que resuelve el problema con poco código de una manera compatible con versiones anteriores. Puede que no resuelva otros problemas, pero dada la antigüedad de este boleto, me gustaría pedir que se reconsidere ese enfoque.

Arreglar esto requiere la instalación a través de sdist, y la última vez que lo discutimos, hubo una gran cantidad de rechazo por parte de las personas que usan herramientas que (aparentemente) necesitan el directorio de origen real. Personalmente, creo que deberíamos tomarnos la molestia y desaprobar los procesos de compilación que no dan los mismos resultados cuando construyes_sdist y luego construyes_wheel como obtienes cuando simplemente construyes_wheel, pero no tengo el tiempo ni la energía para defender esa propuesta. en este momento.

Como alguien que se preocupaba por la construcción en el lugar y, por lo tanto, no le gustaba "siempre debe ir por la ruta sdist": Hace mucho tiempo que hice las paces con la "ruta ir sdist".

Este problema es _muy_ doloroso si se encuentra con él, y el "copiar todo por defecto" tiene poco sentido. Entonces +10 para morder la bala.

La solución de esto requiere la instalación a través de sdist

Había asumido, incorrectamente, que haríamos el cambio con PEP 517.

Sin embargo, estoy totalmente de acuerdo contigo aquí.

IIRC podríamos haberlo hecho, pero los debates que habría desencadenado sobre si la instalación a través de sdist era aceptable fueron demasiada controversia adicional para agregar en ese momento, y como la instalación a través de la copia y la construcción de una rueda todavía era una opción, tomé la menos estresante. curso :-)

Todavía prefiero cambiar a la construcción a través de sdist, pero no tengo tiempo ahora para hacerlo yo mismo.

solución alternativa: utilice un clon poco profundo (cambie la profundidad para adaptarse):

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 y resumir:

  • Los mantenedores de pip están de acuerdo en que esta no es una buena experiencia para los usuarios. Los propios procesos de desarrollo de pip tienen este problema.
  • La razón por la que esto sucede es que pip copia el directorio fuente en un directorio temporal, para asegurarse de que la compilación no dependa de algo fuera de las fuentes.
  • La forma en que queremos resolver este problema es cambiar el comportamiento de pip para construir una distribución de fuente en el árbol, descomprimir la distribución de fuente en un directorio temporal y construir un binario a partir de eso.

Ahora, seguir esta ruta también soluciona un montón de otros problemas de usabilidad relacionados con la mecánica de construcción de pip para los usuarios.

Comencé un proyecto auto-motivado para refactorizar la lógica de construcción de pip. Si bien no abordaré este problema como parte de mi trabajo de refactorización, estoy más que dispuesto a ayudar a alguien que esté lo suficientemente inclinado a intentar solucionar este problema; la solución estaría bastante involucrada en la lógica de compilación de pip, que no es No es el código más sencillo que existe y puede haber casos extremos complicados que solo notamos durante la implementación.

Ah, y como una solución alternativa para esto, agregado en # 6770, pip 19.3 excluirá los directorios .nox y .tox al copiar. Esto debería reducir la cantidad de tiempo que llevarían estas instalaciones, para un número considerable de usuarios.

Esto no resuelve el problema para directorios grandes .git o build ; eso es lo que resolvería el enfoque que elaboré en mi comentario anterior. :)

Esto no resuelve el problema para los directorios grandes .git o build ; eso es lo que resolvería el enfoque que elaboré en mi comentario anterior. :)

Sé que hay algunas herramientas que se basan en .git , pero ¿alguien confía en que se copien build ? Sería bueno agregar eso a los directorios ignorados, feliz de enviar un PR si está de acuerdo.

¿Todavía se está investigando esto? Es una sorpresa muy dolorosa ver que varios gigabytes de volcados de datos de depuración ignorados por git se copian durante una pip install .

Sí, eche un vistazo a los problemas vinculados como # 7555.

Este problema aún persiste, porque el directorio desde el que estoy instalando tiene quizás 10 mb de código Python, pero luego muchos archivos de datos json y .git .

Esto debería ser resuelto por # 7882 (construir directorios locales en su lugar).

Ahora hemos publicado (según # 7951) una versión beta de pip, pip 20.1b1. Esta versión incluye # 7882, que implementó una solución para este problema.

Espero que los participantes en este número nos ayuden probando la versión beta y buscando nuevos errores. Nos gustaría identificar y solucionar cualquier problema potencial antes del lanzamiento principal de 20.1 el martes.

También agradezco la retroalimentación positiva como "¡Sí, funciona mejor ahora!" también, dado que el rastreador de problemas suele estar lleno de "problemas". :)

Diré que es considerablemente mejor.

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

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

¡Funciona muy bien / más rápido para mí! : +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 a 4 segundos, ¡muchas gracias!

¡Gracias por los informes positivos @PythonCoderAS @astrofrog @klamann! :)

Desafortunadamente, ha habido una serie de problemas con la implementación de compilaciones en el lugar (que se están rastreando en el # 7555) lo que significa que, por ahora, necesitamos revertir el # 7882. Como resultado, este problema volverá a ser un problema y, por lo tanto, lo volveremos a abrir. A más largo plazo, esperamos tener una solución que aborde los problemas resueltos con las compilaciones in situ, pero sin el impacto en otros flujos de trabajo que tuvo la solución actual.

Perdón por la interrupción que esto causará.

Desafortunadamente, ha habido una serie de problemas con la implementación de compilaciones in situ.

@pradyunsg gracias por la actualización. Algunos comentarios sobre terminología (siéntase libre de ignorar, solo para su información): esta oración, así como gh-7555, me confundieron porque pip no hace compilaciones en el lugar. Lo que las compilaciones en el lugar siempre han significado es python setup.py build_ext --inplace (o python setup.py develop ).

Aquí cambió el significado a: "compilar sin copiar a un tmpdir". Los módulos de extensión aún no terminan en su lugar, terminan en un directorio build/ que generalmente se limpia fácilmente. Sería bueno ser un poco más explícito, por ejemplo, en gh-7555.

Esa fue originalmente mi redacción. Perdón por cualquier confusión, no sabía que setuptools usaba el término "en el lugar" para significar algo diferente (y todavía no estoy muy seguro de cómo se aplica esa terminología fuera de setuptools). Veremos si podemos encontrar un término más neutral en el futuro (aunque de improviso, no estoy seguro de qué - sugerencias aceptadas con gratitud 😉)

No te preocupes, gracias @pfmoore. Solo pensé en señalarlo, ya que la confusión sobre la terminología a veces puede resultar en hablar entre ellos.

y todavía no estoy muy seguro de cómo se aplica esa terminología fuera de las herramientas de configuración

Para herramientas como CMake y scikit-build, creo que significa lo mismo: realmente en el lugar, los binarios aterrizan junto a las fuentes.

"instalaciones editables" por otro lado es (creo) inventado aquí, y un poco significa "en el lugar que pip es consciente".

aunque de improviso, no estoy seguro de qué: sugerencias aceptadas con gratitud

tal vez solo "compilación local" (frente a la "copia a tmpdir y compilación" actual)?

"instalaciones editables" por otro lado es (creo) inventado aquí, y un poco significa "en el lugar que pip es consciente".

Recientemente tuvimos una larga discusión sobre lo que significa la instalación editable, y creo que en realidad aterrizamos en un lugar que está más en la línea de machine local en lo que respecta a pip. Pero pip no sabe dónde y cómo en la máquina local y es el trabajo de compilación backends para definir y manejar eso.

Podría intentar «compilación en árbol» (similar a «backend PEP 517 en árbol») o «compilación en directorio de origen»

Mi pregunta es, ¿por qué la función no puede ser opcional, por lo que no causa problemas pero puede habilitarse mediante un argumento o algo similar?

Estoy tratando de entender las soluciones para esto, donde una instalación editable no es una opción. ¿Hay alguna?

Una solución alternativa podría ser construir una rueda (usando su backend de compilación directamente) y luego apuntar a pip para instalarla

¿Por qué la función no puede ser opcional, por lo que no causa problemas pero puede habilitarse mediante un argumento o algo similar?

Puede. La razón para revertir el cambio fue que no teníamos ninguna opción de exclusión voluntaria o un período para recibir comentarios sobre el cambio. Tenemos nuevos indicadores para ayudar a facilitar eso (--use-feature y --deprecated-feature), pero alguien tiene que volver a implementar / reintroducir la funcionalidad en este contexto ahora.

En términos generales, creo que lo que queremos hacer aquí es:

  • Agregue un --use-feature = in-tree-build como opción de participación.
  • Cambie el valor predeterminado en una versión posterior con --deprecated-feature = out-of-tree-build como una opción de exclusión + presionando a los usuarios de --use-feature = in-tree-build para que lo eliminen.
  • Elimine ambas opciones en una versión posterior.

Una solución alternativa podría ser construir una rueda (usando su backend de compilación directamente) y luego apuntar a pip para instalarla

Estaba pensando sin un paso de construcción adicional. Pero supongo que nunca debería haber pensado que Python podría salirse con la suya sin los equivalentes de Makefile desde el principio.

¿Fue útil esta página
0 / 5 - 0 calificaciones