Python threading.thread.start () no devuelve el control al hilo principal

Estoy intentando un progtwig que ejecuta un fragmento de código de tal manera que el usuario pueda detener su ejecución en cualquier momento sin detener el progtwig principal. Pensé que podía hacer esto usando threading.Hilo, pero luego ejecuté el siguiente código en IDLE (Python 3.3):

from threading import * import math def f(): eval("math.factorial(1000000000)") t = Thread(target = f) t.start() 

La última línea no regresa: finalmente reinicié el shell. ¿Es esto una consecuencia del locking global de intérpretes, o estoy haciendo algo mal? No vi nada específico a este problema en la documentación de subprocesos ( http://docs.python.org/3/library/threading.html )

Intenté hacer lo mismo usando un proceso:

 from multiprocessing import * import math def f(): eval("math.factorial(1000000000)") p = Process(target = f) p.start() p.is_alive() 

La última línea devuelve False, ¡aunque lo ejecuté solo unos segundos después de comenzar el proceso! Basado en el uso de mi procesador, me veo forzado a concluir que el proceso nunca comenzó en primer lugar. ¿Puede alguien explicar por favor lo que estoy haciendo mal aquí?

Thread.start () nunca regresa! ¿Podría esto tener algo que ver con la implementación en C de la biblioteca matemática?

Como @eryksun señaló en el comentario: math.factorial () se implementa como una función C que no libera GIL, por lo que ningún otro código de Python puede ejecutarse hasta que regrese.

Nota: la versión de multiprocessing debería funcionar como está: cada proceso de Python tiene su propia GIL.


factorial(1000000000) tiene cientos de millones de dígitos. Trate de import time; time.sleep(10) import time; time.sleep(10) como cálculo ficticio en su lugar.

Si tiene problemas con el código de multiproceso en IDLE, intente el mismo código desde la línea de comandos para asegurarse de que el error persista.

Si p.is_alive() devuelve False después de que p.start() ya se haya llamado, entonces podría significar que hay un error en la función f() , por ejemplo, MemoryError .

En mi máquina, p.is_alive() devuelve True y uno de los CPU está al 100% si pego su código de la pregunta en el shell de Python.

Sin relación: elimine las importaciones de comodines, por ejemplo, from multiprocessing import * . Pueden ocultar otros nombres en su código, de modo que no puede estar seguro de lo que significa un nombre dado, por ejemplo, los threading podrían definir la función eval (no lo hace, pero podría) con una semántica similar pero diferente que podría romper su código en silencio.

Quiero que mi progtwig pueda manejar las entradas ridículas del usuario con gracia

Si pasa la entrada del usuario directamente a eval() entonces el usuario puede hacer cualquier cosa .

¿Hay alguna manera de obtener un proceso para imprimir, digamos, un mensaje de error sin construir una tubería u otra estructura similar?

Es un código común de Python:

 print(message) # works 

La diferencia es que si varios procesos ejecutan print() , la salida podría estar distorsionada. Podría usar un locking para sincronizar print() llamadas de print() .