2012-06-13 19 views
15

Nuestro proyecto Django es cada vez más grande. Tenemos cientos de aplicaciones y utilizamos una tonelada de paquetes de python de terceros, muchos de los cuales necesitan tener C compilado. Nuestras implementaciones demoran mucho tiempo cuando necesitamos crear un nuevo entorno virtual para las principales versiones. Dicho esto, estoy buscando acelerar las cosas, comenzando con Pip. ¿Alguien sabe de un tenedor de Pip que instalará paquetes en paralelo?Instalación en paralelo de Pip

pasos que he tomado hasta ahora:

  • He mirado para un proyecto que hace precisamente esto con poco éxito. Encontré este Github Gist: https://gist.github.com/1971720 pero los resultados son casi exactamente los mismos que nuestro amigo de un solo hilo.

  • Luego encontré el proyecto Pip en Github y comencé a buscar a través de la red de horquillas para ver si podía encontrar algún compromiso que mencionara que hacía lo que estaba intentando hacer. Es un desastre allí. Lo intentaré y trataré de ponerlo en paralelo, si tengo que hacerlo, solo quiero evitar pasar el tiempo haciendo eso.

  • Vi una charla en DjangoCon 2011 de ep.io explicando sus instrucciones de implementación y mencionan paralelizar pip, enviar archivos .so en lugar de compilar C y duplicar Pypi, pero no mencionaron cómo lo hicieron o lo que usaron

+0

usar máquinas virtuales como su unidad de despliegue y hacer que todo el Sistema Operativo (Debian) paquetes es lo que hacemos. A continuación, puede ejecutar su propio repositorio y realizar actualizaciones graduales sin problemas y completar las instalaciones. Tener paquetes de sistema operativo preconstruidos es una gran manera de asegurarse de que tenga una instalación repetible, y puede hacer que dependan de cosas que no sean de Python como apache o nginx. –

+0

@ NickCraig-Wood Aunque es una gran idea, no tenemos suficiente tiempo para convertir todos los paquetes de python en las versiones que usamos para .debs. Ya ejecutamos todo encima de KVM. Solo necesitamos que las implementaciones sean más rápidas lo antes posible. – Kyle

+0

Esta es una vieja pregunta, pero hoy en día puede construir un caché de caseta de gobierno de pip que reduce considerablemente el tiempo de instalación del paquete. –

Respuesta

7

¿Ha analizado el proceso de implementación para ver dónde va realmente el tiempo? Me sorprende que ejecutar múltiples procesos paralelos de pip no lo acelere demasiado.

Si el tiempo va para consultar PyPI y encontrar los paquetes (en particular cuando también se descarga desde Github y otras fuentes), entonces puede ser beneficioso configurar su propia PyPI. Puede alojar PyPI mismo y añadir lo siguiente a su archivo requirements.txt (docs):

--extra-index-url YOUR_URL_HERE 

o el siguiente si desea reemplazar los PyPI oficiales por completo:

--index-url YOUR_URL_HERE 

Esto puede acelerar los tiempos de descarga como todos los paquetes ahora se encuentran en una máquina cercana.

También se dedica mucho tiempo a compilar paquetes con código C, como PIL. Si esto resulta ser el cuello de botella, vale la pena investigar el código de compilación en múltiples procesos. Incluso puede compartir binarios compilados entre sus máquinas (pero muchas cosas deberían ser similares, como sistema operativo, longitud de palabra de la CPU, etc.)

+0

Mi primer paso fue reflejar Pypi usando z3c.pypimirror y eso ayudó. Creo que el siguiente paso es usar binarios para cosas que necesitan ser compiladas o paralelizar. Hice mi mejor esfuerzo para dar sentido a lo que está sucediendo en el código de Gist. Creo que está programando el subproceso y se está ejecutando en un momento posterior. No estoy seguro de cómo asegurarse de que todos los subprocesos se ejecuten al mismo tiempo usando gevent. – Kyle

+0

Si quieres acelerar las compilaciones he tenido mucha suerte con ccache en el pasado. –

3

¿Te ayuda si tienes tu sistema de compilación (por ejemplo, Jenkins?) construir e instalar todo en un directorio de entorno virtual específico de construcción? Cuando la compilación tiene éxito, usted puede hacer que el entorno virtual sea reubicable, instalarlo y enviar el tablall resultante a su almacenamiento "tarballs liberados". En el momento del despliegue, debe tomar el archivo tarball más reciente y descomprimirlo en el host de destino y luego debe estar listo para ejecutarse. Entonces, si lleva 2 segundos descargar el archivo tar y 0.5 segundos para descomprimirlo en el host de destino, su implementación demorará 2.5 segundos.

La ventaja de este enfoque es que todas las instalaciones de paquetes ocurren en tiempo de compilación, no en tiempo de implementación.

advertencia: su trabajador de sistema de compilación que construye/compila/instala cosas en un entorno virtual debe usar la misma arquitectura que el hardware de destino.Además, su sistema de aprovisionamiento de caja de producción tendrá que ocuparse de varias dependencias de biblioteca C que algunos paquetes Python pueden tener (por ejemplo, PIL requiere que libjpeg instalado antes de poder compilar código relacionado con JPEG, también se romperán si libjpeg no está instalado en el destino caja)

Funciona bien para nosotros.

Haciendo una reubicable env virtual:

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

En este ejemplo build-1123423 es un directorio virtual de env-construcción específica.

6

instalación pip paralelo

En este ejemplo se utiliza xargs para paralelizar el proceso de construcción en aproximadamente 4x. Puede aumentar el factor de paralelización con max-procs a continuación (mantenerlo aproximadamente igual a su número de núcleos).

Si está intentando, por ejemplo, acelere un proceso de creación de imágenes que está haciendo una y otra vez, podría ser más fácil y definitivamente reducir el consumo de ancho de banda para obtener una imagen directamente en el resultado en lugar de hacer esto cada vez, o construir su imagen usando pip -t o virtualenv.

Descargar e instalar paquetes en paralelo, cuatro a la vez:

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

Nota: xargs tiene diferentes nombres de parámetros en diferentes distribuciones de Linux. Consulte la página del manual de su distribución para obtener detalles.

Lo mismo inline utilizando un 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 

Advertencia: hay una posibilidad remota de que la velocidad de este método podría confundir a los manifiestos de paquetes (dependiendo de la distribución) en caso de intento múltiple de pip para instalar la misma dependencia exactamente al mismo tiempo, pero es muy poco probable si solo estás haciendo 4 a la vez. Podría arreglarse fácilmente por pip install --uninstall depname.

+1

Refresque el truco pero odiaría tener que depurar un problema de dependencia :) ¿Cómo usted vino por esa orden? –

+0

Gracias @ItamarHaber ... y estoy de acuerdo, eso no sería divertido :) es un fragmento del archivo de paquetes que normalmente uso (que estaba alfabetizado en un punto). Spooky es especialmente genial para trabajar con Redis (como es shortuuid que parece no estar en esta lista). –

-1

Inspirado por Jamieson Becker's answer, modifiqué una secuencia de comandos de instalación para hacer instalaciones paralelas de pip y parece que hay una mejora. Mi script bash ahora contiene un fragmento como este:

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 

Al menos puedo buscar problemas manualmente.

+0

Debe usar un archivo de requisitos (por ejemplo, 'pip install -r requirements.txt'). Lo que es menos importante, Bash permite nuevas líneas en cadenas, por lo que no es necesario cerrar la cadena y escapar de la nueva línea – Leons

8

Basándose en la respuesta de Jamieson Becker, el siguiente código hace una descarga paralela de Pip, luego instala rápidamente los paquetes.

Primero, descargamos paquetes en paralelo en un directorio de distribución ("dist"). Esto se ejecuta fácilmente en paralelo sin conflictos. Cada nombre del paquete que se imprime se imprime antes de la descarga, lo que ayuda a eliminar errores. Para obtener ayuda adicional, cambie -P9 a -P1, para descargar secuencialmente.

Después de la descarga, el siguiente comando le dice a Pip que instale/actualice los paquetes. Los archivos no se descargan, se extraen del directorio local rápido.

Es compatible con la versión actual de Pip 1.7, también con Pip 1.5.

Para instalar solo un subconjunto de paquetes, reemplace la instrucción 'cat requirements.txt' con su comando personalizado, p. '-v egrep github requirement.txt'

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

pip install --no-index --find-links=./dist -r ./requirements.txt 
+2

¡Me gusta! Esto será más lento (no paraleliza la instalación real en caso de que esté compilando extensiones C), pero esto evita muy bien cualquier problema de escritura concurrente. Buena idea. –

+0

Tenga cuidado ya que, lamentablemente, esto puede arruinar fácilmente las versiones de las dependencias. Pero si todas las versiones de la biblioteca están restringidas (con el modificador -c), debería funcionar bien. – allprog

Cuestiones relacionadas