2009-11-08 13 views
11

Estoy tratando de usar subprocesos en un proyecto de Python en el que estoy trabajando, pero los subprocesos no parecen comportarse como deberían en mi código. Parece que todos los subprocesos se ejecutan secuencialmente (es decir, el subproceso2 se inicia después de que finaliza el subproceso 1, ambos no se inician al mismo tiempo). Escribí un script simple para probar esto, y eso también ejecuta hilos secuencialmente.El subproceso de Python parece ejecutar subprocesos

import threading 

def something(): 
    for i in xrange(10): 
     print "Hello" 

def my_thing(): 
    for i in xrange(10): 
     print "world" 

threading.Thread(target=something).start() 
threading.Thread(target=my_thing).start() 

Aquí está la salida que recibo de ejecutarlo:

Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
world 
world 
world 
world 
world 
world 
world 
world 
world 
world 

El mismo comportamiento se observa con mucho mayor número de iteraciones de los bucles.

Intenté buscar en la web y SO más antiguas, pero no encontré nada que me ayudara. ¿Puede alguien indicar qué problema tiene este código?

Respuesta

13

Actualmente en python, los hilos se cambian después de ejecutar una cierta cantidad especificada de instrucciones de bytecode. No se ejecutan al mismo tiempo. Solo tendrá subprocesos ejecutándose en paralelo cuando uno de ellos llame a algún módulo intensivo de E/S o que no tenga Python que pueda liberar GIL (bloqueo de intérprete global).

Estoy bastante seguro de que obtendrá la salida mezclada si aumenta el número de bucles a algo así como 10000. Recuerde que simplemente generar el segundo hilo también lleva "mucho" tiempo.

+0

Mismo comportamiento con 10000 iteraciones – MAK

+0

En el proyecto real en el que estoy trabajando, uno de los subprocesos es un ciclo infinito que escucha mensajes y llama a una función de devolución de llamada como ellos llegan. Simplemente bloquea todos los otros hilos. Lamentablemente, el código de bucle real no se puede modificar (simplemente invoco el método run() de una clase dentro del hilo). – MAK

+0

Cuando ejecuto el script de esta manera: './pythr.py | uniq -c' Obtengo: 8969 Hola | 1 Hola mundo | 6626 mundial | 1 | 3373 mundial | 1030 Hola. Por lo tanto, cambia el control, aunque no tan a menudo ... – viraptor

10

En el tiempo que toma el segundo hilo para iniciar los primeros bucles de hilo e imprime ya.

Aquí se ve así, se puede ver el segundo hilo comenzando después de que el primero emitió algunos saludos.

Hello 
Hello 
Hello 
Hello 
Hello 
Helloworld 

Helloworld 

Helloworld 

Helloworld 

Helloworld 

world 
world 
world 
world 
world 

Btw: Su ejemplo no es significativo en absoluto. La única razón para Threads es IO, y IO es lento. Cuando se agrega un poco de dormir para simular IO que debería funcionar como se esperaba: aparece

import threading 
from time import sleep 

def something(): 
    for i in xrange(10): 
     sleep(0.01) 
     print "Hello" 

def my_thing(): 
    for i in xrange(10): 
     sleep(0.01) 
     print "world" 

threading.Thread(target=something).start() 
threading.Thread(target=my_thing).start() 

una mezcla salvaje:

worldHello 

Helloworld 

Helloworld 

worldHello 

Helloworld 

Helloworld 

worldHello 

Helloworld 

worldHello 

Helloworld 
+2

No obtengo una salida así incluso con un número de iteraciones mucho mayor/más pequeño de los bucles for. En mi computadora, siempre es secuencial. Creo que esto depende del sistema operativo/procesador, como sugirió abyx. – MAK

+0

Como dije en mi pregunta, este es solo un ejemplo para mi problema, no el código con el que estoy trabajando (que es mucho más grande). En mi código actual, uno de los hilos ejecuta un bucle para escuchar las señales dbus. – MAK

3

Esto realmente depende de planificador de su sistema operativo, el procesador.
Aparte de eso, se sabe que los hilos de CPython no son perfectos debido al GIL (PDF), lo que, en resumen, significa que muchas veces los hilos se ejecutan secuencialmente, o algo por el estilo.

+2

Probablemente quiera decir que los hilos de CPython sufren de GIL ... No hay GIL en, digamos, Jython. – EOL

+0

@EOL - tiene razón, actualicé la respuesta – abyx

4

El comportamiento también puede cambiar dependiendo de si el sistema está utilizando tiene un solo procesador o varios procesadores, como se explica en this talk por David Beazley.

Como dice viraptor, el primer subproceso liberará el GIL después de ejecutar sys.getcheckinterval() bytecodes (100 de manera predeterminada). Para resumir crudamente lo que dice David Beazley, en un sistema de procesador único, el segundo hilo tendrá la oportunidad de hacerse cargo. Sin embargo, en un sistema multinúcleo, el segundo subproceso puede estar ejecutándose en un núcleo diferente, y el primer subproceso intentará readquirir el bloqueo y probablemente tenga éxito, ya que el sistema operativo no habrá tenido tiempo de cambiar procesadores. Esto significa que en un sistema multinúcleo con una hebra enlazada a la CPU, es posible que los otros subprocesos nunca se vean.

El camino a seguir es agregar una sentencia sleep a ambos lazos para que dejen de serlo CPU vinculada.

Cuestiones relacionadas