hilos de Python se implementan utilizando hebras de SO en todas las implementaciones que conozco (C Python, PyPy y Jython). Para cada subproceso de Python, hay una secuencia de sistema operativo subyacente.
Algunos sistemas operativos (Linux es uno de ellos) muestran todos los subprocesos lanzados por el mismo ejecutable en la lista de todos los procesos en ejecución. Este es un detalle de implementación del sistema operativo, no de Python. En algunos otros sistemas operativos, es posible que no vea esos subprocesos al enumerar todos los procesos.
El proceso terminará cuando finalice el último hilo que no sea daemon. En ese punto, todos los hilos daemon serán terminados. Entonces, esos subprocesos son parte de su proceso, pero no impiden que finalicen (mientras que un hilo regular lo evitará). Eso se implementa en Python puro. Un proceso finaliza cuando se llama a la función del sistema _exit
(matará a todos los hilos), y cuando el hilo principal finaliza (o se llama al sys.exit
), el intérprete de Python verifica si hay otro hilo que no sea daemon en ejecución. Si no hay ninguno, llama al _exit
, de lo contrario, espera a que finalicen los subprocesos no daemon.
La bandera hilo de utilidad se implementa en Python puro por el módulo de threading
. Cuando se carga el módulo, se crea un objeto Thread
para representar el hilo principal, y su método _exitfunc
se registra como un gancho atexit
.
El código de esta función es:
class _MainThread(Thread):
def _exitfunc(self):
self._Thread__stop()
t = _pickSomeNonDaemonThread()
if t:
if __debug__:
self._note("%s: waiting for other threads", self)
while t:
t.join()
t = _pickSomeNonDaemonThread()
if __debug__:
self._note("%s: exiting", self)
self._Thread__delete()
Esta función será llamado por el intérprete de Python cuando sys.exit
se llama, o cuando el hilo principal termina. Cuando la función retorna, el intérprete llamará a la función del sistema _exit
. Y la función terminará, cuando solo hay hilos daemon en ejecución (si hay alguno).
Cuando se llama a la función _exit
, el sistema operativo terminará todos los procesos y luego finalizará el proceso. El tiempo de ejecución de Python no llamará a la función _exit
hasta que todo el subproceso no-demonio esté listo.
Todos los hilos son parte del proceso.
Mi interpretación/comprensión era: hilo principal termina cuando se terminan todos los hilos no demonio.
Por lo tanto, los subprocesos de daemon de python no son parte del programa de Python si "todo el programa Python se cierra cuando solo quedan subprocesos de daemon"?
Su comprensión es incorrecta. Para el sistema operativo, un proceso se compone de muchos hilos, todos iguales (no hay nada especial sobre el hilo principal para el sistema operativo, excepto que el tiempo de ejecución de C agrega una llamada al _exit
al final de la función main
). Y el sistema operativo no sabe acerca de los hilos daemon. Esto es puramente un concepto de Python.
El intérprete de Python utiliza el hilo nativo para implementar el hilo de Python, pero tiene que recordar la lista de hilos creados. Y utilizando su gancho atexit
, asegura que la función _exit
regresa al sistema operativo solo cuando finaliza el último subproceso no-demonio. Al usar "todo el programa Python", la documentación se refiere a todo el proceso.
El siguiente programa puede ayudar a entender la diferencia entre el hilo de utilidad e hilo normal:
import sys
import time
import threading
class WorkerThread(threading.Thread):
def run(self):
while True:
print 'Working hard'
time.sleep(0.5)
def main(args):
use_daemon = False
for arg in args:
if arg == '--use_daemon':
use_daemon = True
worker = WorkerThread()
worker.setDaemon(use_daemon)
worker.start()
time.sleep(1)
sys.exit(0)
if __name__ == '__main__':
main(sys.argv[1:])
Si se ejecuta este programa con el '--use_daemon', se verá que el programa sólo se imprima un pequeño número de líneas Working hard
. Sin esta bandera, el programa no terminará incluso cuando finalice el hilo principal, y el programa imprimirá líneas Working hard
hasta que se mate.
Quieres decir 'threading.Thread' ¿no? –
Sí, lo hago. ¿Hay otros hilos en Python estándar? – warvariuc
Sí, el módulo 'thread' proporciona otra interfaz para threads nativos (pero hey usa la misma implementación nativa). –