El día 4 de marzo de 2014, 10:00, Daπid <[email protected]> escribió: > 2014-03-03 22:19 GMT+01:00 Chema Cortes <[email protected]>: >> >> >> OK. Creo que has hecho un planteamiento demasiado optimista. El >> proceso "saver" entra a funcionar antes de los jobs generadores, por >> lo que es posible que termine sin haber procesado todos los datos, >> bloqueándose el hilo principal por quedar datos en la cola. > > > El proceso real crea el fichero en el que va a guardar los datos, y no > termina hasta que recibe un None, en cuyo caso sólo tiene que cerrar el > archivo y terminar casi inmediatamente. > >> Por otro lado, estás usando una librería externa para HDF5 que podría >> estar descontrolando el GIL del intérprete. Prueba a usar el backend >> "threading" a ver si mejora. >> >> https://pythonhosted.org/joblib/parallel.html#using-the-threading-backend > > > En mi caso, eso no es una opción. El cálculo tira mucho de CPU, y necesito > hacer uso de los ocho núcleos que tengo. Cierto es que la parte "dura" del > cálculo está en Cython y podía ejecutarla con nogil. Lo que estoy haciendo > ahora es simplemente poner los resultados en memoria y guardarlos todos > seguidos al final. Por otro lado, convertir el proceso "saver" en un thread > es probablemente una buena idea. > > Lo sospechoso es que en la mayoría de los casos, funciona. Si estuviera > haciendo algo mal, debería fallar siempre; no funcionar para ciertos > conjuntos de datos y fallar para otros muy similares. Huele a bug en Python, > pero no estoy seguro.
Python está bien para muchas cosas, pero no está preparado para multiproceso. No te creas que por usar el módulo "multiprocessing" tu código va a ser mucho más rápido que usando "multihilo" sobre un sólo core, del mismo modo que un hipotético intérprete sin-GIL no va a ser más rápido que uno con-GIL. Para poder tener multiproceso, de tu proceso padre se lanzan varios fork, estableciéndose un conjunto de dispatchers que serializan/deserializan todos tus datos compartidos. Cuantos más cambios se hagan en estos datos, peor rendimiento tienes, y más probabilidades de que se queden bloqueados los procesos. Así mismo, los datos se duplican para cada proceso, con el conocido problema (en concurrencia) de que queden en estado inconsistente y que haga que los GCs de cada proceso no terminen por liberar la memoria. Es fundamental tener un diseño bien pensado. No basta con hacer que funcione con "multiprocessing": hay que granular con cuidado quiénes van a ver qué parte de los datos y quiénes podrán modificarlos. A veces es mejor tener un sólo proceso que pueda modificar y que el resto se comunique con él para que haga los cambios, nada de memoria compartida por todos. Mejor aún, que cada proceso tenga su datos privados y que se comuniquen mediante mensajes siguiendo el patrón "Actor". Mi consejo es que intentes usar el backend "threading" a ver si funciona sin problemas. Lo que vaya sin GIL, como las librerías para HDF5 o lo que quieras calculas con Cython-nogil, intenta que pase los datos a través de un mecanismo que no comparta memoria con python. Así mismo, es importante revisar todo el código. Cualquier variable global puede ser importante. Nada debería haber suelto por el módulo. Es complejo dar con un problema de concurrencia sin ver el código completo. No sé si te sirve de algo lo que te he dicho, pero hace tiempo que me pasé a scala para el multiproceso. Aquí te pongo un artículo que lo explica bastante bien: http://www.chrisstucchio.com/blog/2013/why_not_python.html -- Hyperreals *R "Quarks, bits y otras criaturas infinitesimales": http://ch3m4.org/blog Buscador Python Hispano: http://ch3m4.org/python-es _______________________________________________ Python-es mailing list [email protected] https://mail.python.org/mailman/listinfo/python-es FAQ: http://python-es-faq.wikidot.com/
