importar dentro de un hilo de Python

Tengo algunas funciones que cargan módulos de python de forma interactiva usando __import__

Recientemente me topé con algún artículo sobre un “locking de importación” en Python, es decir, un locking específicamente para importaciones (no solo el GIL). Pero el artículo era viejo, así que quizás eso ya no sea verdad.

Esto me hace preguntarme acerca de la práctica de importar en un hilo.

  1. ¿ __import__ seguro el hilo import / __import__ ?
  2. ¿Pueden crear cerraduras muertas?
  3. ¿Pueden causar problemas de rendimiento en una aplicación con hilos?

EDITAR 12 Sept 2012

Gracias por la gran respuesta de Soravux. Por lo tanto, la importación es segura para subprocesos y no me preocupan los interlockings, ya que las funciones que usan __import__ en mi código no se llaman entre sí.

¿Sabe si el locking se ha adquirido incluso si el módulo ya se ha importado? Si ese es el caso, probablemente debería buscar en sys.modules para verificar si el módulo ya se ha importado antes de llamar a __import__ .

Claro que esto no debería hacer mucha diferencia en CPython, ya que de todos modos está el GIL. Sin embargo, podría hacer una gran diferencia en otras implementaciones como Jython o python sin stack.

EDITAR 19 Sept 2012

Acerca de Jython, esto es lo que dicen en el documento:

http://www.jython.org/jythonbook/en/1.0/Concurrency.html#module-import-lock

Python, sin embargo, define un locking de importación de módulo, que es implementado por Jython. Este locking se adquiere siempre que se realiza una importación de cualquier nombre. Esto es cierto ya sea que la importación pase por la statement de importación, el __import__ incorporado equivalente o el código relacionado. Es importante tener en cuenta que incluso si el módulo correspondiente ya se ha importado, el locking de importación del módulo aún se adquirirá, aunque solo sea brevemente.

Por lo tanto, parece que tendría sentido verificar en sys.modules antes de realizar una importación, para evitar la adquisición del locking. ¿Qué piensas?

Las importaciones normales son seguras para subprocesos porque adquieren un locking de importación antes de la ejecución y lo liberan una vez que se realiza la importación. Si agrega sus propias importaciones personalizadas utilizando los ganchos disponibles, asegúrese de agregarle este esquema de locking. Se puede acceder a las instalaciones de locking en Python mediante el módulo imp ( imp.lock_held() / acquire_lock() / release_lock() ).

El uso de este locking de importación no creará ningún interlocking o error de dependencia aparte de las dependencias circulares que ya se conocen .

La llamada de bajo nivel para crear un subproceso que se está clone en Linux, el subprocesamiento en Python es una operación similar a un fork. Bifurcación y clonación aplica diferentes comportamientos en los distintos segmentos de memoria. Por ejemplo, solo la stack no es compartida por subprocesos, en comparación con las bifurcaciones que clonan más segmentos (Datos (a menudo COW), Stack, Code, Heap), que efectivamente no comparten su contenido. El mecanismo de importación en Python utiliza el espacio de nombres global que no se coloca en la stack, por lo tanto, utiliza un segmento compartido con sus hilos. Dado que los efectos secundarios (es decir, los cambios en la memoria) de la importación funcionan en los mismos segmentos, se comporta como un progtwig de un solo hilo. Sin embargo, tenga cuidado de usar bibliotecas seguras para subprocesos en sus importaciones en progtwigs de multiproceso. Esto causará que caos use llamadas a funciones que no son seguras para subprocesos en dicho entorno.

Por cierto, los progtwigs de subprocesos en Python sufren el GIL que no permitirá muchas mejoras de rendimiento a menos que su progtwig esté enlazado a E / S o dependa de C o bibliotecas externas seguras para subprocesos (ya que liberan el GIL antes de ejecutarse). Al ejecutarse en dos subprocesos, la misma función importada no se ejecutará simultáneamente debido a este GIL. Tenga en cuenta que esto es solo una limitación de CPython y otras implementaciones de Python tendrán un comportamiento diferente.

Para responder a su edición: Python almacena en caché todos los módulos importados. Si el módulo ya está cargado en el caché, no se ejecutará de nuevo y la statement de importación (o función) se devolverá de inmediato. No tiene que implementar usted mismo la búsqueda de caché en sys.modules, Python lo hace por usted y no bloqueará nada, aparte de GIL para la búsqueda de sys.modules.

Para responder a su segunda edición: prefiero tener que mantener un código más simple que intentar optimizar las llamadas a las bibliotecas que utilizo (en este caso, la biblioteca estándar). La razón es que el tiempo requerido para realizar algo suele ser mucho más importante que el tiempo requerido para importar el módulo que lo hace. Además, el tiempo requerido para mantener este tipo de código a lo largo del proyecto es mucho mayor que el tiempo que tomará para ejecutarse. Todo se reduce a: “el tiempo del progtwigdor es más valioso que el tiempo de CPU”.