hilos - ¿Qué es un hilo de Python?
comunicacion entre hilos python (4)
Los hilos de Python son prácticamente una implementación de intérprete, debido al llamado bloqueo de intérprete global (GIL), incluso si técnicamente está utilizando los mecanismos de subprocesamiento de nivel de os. On * nix está utilizando los pthreads, pero el GIL lo convierte en un hito híbrido para el paradigma de enhebrado a nivel de aplicación. Por lo tanto, lo verá en los sistemas * nix varias veces en una salida ps / top, pero aún se comporta (en cuanto al rendimiento) como un subproceso implementado por software.
No, solo está viendo el tipo de implementación de subproceso subyacente de su sistema operativo. Este tipo de comportamiento está expuesto por * nix subthread-like threading o me he dicho que windows incluso implementa hilos de esta manera.
Cuando su programa se cierra, espera a que todos los hilos terminen también. Si tiene subprocesos, lo que podría posponer la salida indefinidamente, puede ser conveniente marcar esos subprocesos como "demonios" y permitir que su programa termine incluso si esos subprocesos aún se están ejecutando.
Algún material de referencia que pueda interesarle:
Tengo varias preguntas con respecto a los hilos de Python.
- ¿Es un hilo de Python una implementación de Python o OS?
- Cuando uso htop, un script de subprocesos múltiples tiene múltiples entradas: el mismo consumo de memoria, el mismo comando pero un PID diferente. ¿Esto significa que un hilo [de Python] es realmente un tipo especial de proceso? (Sé que hay una configuración en htop para mostrar estos hilos como un proceso -
Hide userland threads
) - Documentation dice:
Un hilo se puede marcar como un "hilo daemon". La importancia de esta bandera es que todo el programa Python sale cuando solo quedan subprocesos de daemon.
Mi interpretación / comprensión fue: el hilo principal finaliza cuando todos los hilos no daemon terminan.
Entonces, los subprocesos de daemon python no son parte del programa Python si "todo el programa Python se cierra cuando solo quedan subprocesos de daemon"?
Los subprocesos de Python se implementan usando subprocesos del sistema operativo 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 subproceso no demoníaco. 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
_exit
función_exit
del sistema (matará a todos los hilos), y cuando el hilo principal finaliza (o sesys.exit
), el intérprete de Python comprueba si hay otro hilo no daemon ejecutándose. Si no hay ninguno, llama a_exit
, de lo contrario, espera a que finalicen los subprocesos no daemon.
El indicador de subproceso daemon se implementa en Python puro mediante 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 hook 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()
El intérprete de Python sys.exit
esta sys.exit
cuando se sys.exit
o cuando finalice el hilo principal. Cuando la función retorna, el intérprete llamará a la función _exit
del sistema. Y la función terminará, cuando solo hay hilos daemon en ejecución (si hay alguno).
Cuando se _exit
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 fue: el hilo principal finaliza cuando todos los hilos no daemon terminan.
Entonces, los hilos de daemon de python no son parte del programa de Python si "todo el programa de Python se cierra cuando solo quedan subprocesos de daemon"?
Tu comprensión es incorrecta Para el sistema operativo, un proceso se compone de muchos hilos, todos los cuales son 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 a _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 usa el hilo nativo para implementar el hilo de Python, pero tiene que recordar la lista de hilos creados. Y utilizando su hook atexit
, garantiza que la función _exit
regrese al sistema operativo solo cuando termine el último hilo no daemon. Al usar "todo el programa Python", la documentación se refiere a todo el proceso.
El siguiente programa puede ayudar a comprender la diferencia entre el hilo del daemon y el hilo común:
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 ejecuta este programa con ''--use_daemon'', verá que el programa solo imprimirá una pequeña cantidad de líneas Working hard
de Working hard
. Sin esta bandera, el programa no terminará incluso cuando termine el hilo principal, y el programa imprimirá líneas Working hard
hasta que se elimine.
Hay excelentes respuestas a la pregunta, pero creo que la cuestión de los hilos de daemon aún no se explica de manera simple. Entonces, esta respuesta se refiere solo a la tercera pregunta
"el hilo principal finaliza cuando todos los subprocesos no daemon terminan".
Entonces, los subprocesos de daemon python no son parte del programa Python si "todo el programa Python se cierra cuando solo quedan subprocesos de daemon"?
Si piensas en lo que es un daemon, generalmente es un servicio . Algún código que se ejecuta en un bucle infinito, que sirve solicitudes, llena colas, acepta conexiones, etc. Otros hilos lo usan. No tiene ningún propósito cuando se ejecuta solo ( en términos de un solo proceso ).
Por lo tanto, el programa no puede esperar a que finalice el hilo del daemon, porque puede que nunca suceda. Python finalizará el programa cuando todos los subprocesos no daemon se completen. También detiene los hilos daemon .
Para esperar hasta que un hilo daemon haya completado su trabajo, use el método join()
. daemon_thread.join()
hará que Python también espere el hilo del daemon antes de salir. The join()
también acepta un argumento de tiempo de espera .
No estoy familiarizado con la implementación, así que hagamos un experimento:
import threading
import time
def target():
while True:
print ''Thread working...''
time.sleep(5)
NUM_THREADS = 5
for i in range(NUM_THREADS):
thread = threading.Thread(target=target)
thread.start()
El número de subprocesos informados utilizando
ps -o cmd,nlwp <pid>
esNUM_THREADS+1
(uno más para el subproceso principal), por lo que siempre que las herramientas del SO detecten el número de subprocesos, deberían ser subprocesos del sistema operativo. Intenté ambos con cpython y jython y, a pesar de que en jython hay otros hilos en ejecución, por cada hilo adicional que agregue,ps
incrementa el número de hilos en uno.No estoy seguro sobre el comportamiento de
htop
, perops
parece ser consistente.Agregué la siguiente línea antes de comenzar los hilos:
thread.daemon = True
Cuando ejecuté el uso de cpython, el programa finalizó casi de inmediato y no se encontró ningún proceso utilizando
ps
, así que supongo que el programa terminó junto con los hilos. En jython, el programa funcionó de la misma manera (no terminó), así que tal vez haya otros subprocesos del jvm que impidan que el programa finalice o los subprocesos del daemon no sean compatibles.
Nota: utilicé Ubuntu 11.10 con python 2.7.2+ y jython 2.2.1 en java1.6.0_23