2011-05-24 11 views
19

Estoy un poco confundido acerca de cómo escribir código asincrónico en python/twisted. Supongamos (para bien de los argumentos) que estoy exponiendo una función para el mundo, que tendrá un número y devolver True/False si es primo/no preferencial, por lo que parece vagamente a esto:Twisted: Haciendo código no bloqueante


def IsPrime(numberin): 
    for n in range(2,numberin): 
     if numberin % n == 0: return(False) 
    return(True) 

(sólo para ilustrar).

Digamos que hay un servidor web que necesita llamar a IsPrime en función de un valor enviado. Esto llevará mucho tiempo para grandes numberin.

Si mientras tanto otro usuario solicita la primalidad de un número pequeño, ¿hay alguna manera de ejecutar las dos llamadas de función de forma asincrónica utilizando la arquitectura reactor/diferido para que el resultado de la calcificación breve se devuelva antes del resultado de el largo calc?

Entiendo cómo hacer esto si la funcionalidad IsPrime proviene de algún otro servidor web al cual mi servidor web haría un getPage diferido, pero ¿y si solo fuera una función local?

es decir, ¿se puede torcer de alguna manera el tiempo compartido entre las dos llamadas a IsPrime, o requeriría una invocación explícita de un nuevo hilo?

O, ¿el bucle IsPrime necesita ser fragmentado en una serie de bucles más pequeños para que el control pueda pasar rápidamente al reactor?

¿O algo más?

+3

Cuando tiene una función que realmente lleva mucho tiempo, por ej. está "bloqueando", puede usar 'deferToThread()' para ejecutarlo en un hilo: http://twistedmatrix.com/documents/11.0.0/api/twisted.internet.threads.deferToThread.html –

+1

O Twisted's Process soporte: http://twistedmatrix.com/documents/current/core/howto/process.html –

+0

Hah, escribí una [pregunta muy similar] (http://stackoverflow.com/questions/5719782/confusion-about-cpu -intensive-code-in-node-js) para Node.js recientemente. Interesado en ver cuáles son las soluciones en Twisted. – YXD

Respuesta

26

Creo que su comprensión actual es básicamente correcta. Twisted es solo una biblioteca de Python y el código de Python que se escribe para usarlo se ejecuta normalmente como cabría esperar del código de Python: si solo tiene un único hilo (y un único proceso), solo sucede una cosa a la vez. Casi ninguna API provista por Twisted crea hilos o procesos nuevos, por lo que, en el curso normal de las cosas, su código se ejecuta secuencialmente; isPrime no se puede ejecutar por segunda vez hasta que haya terminado de ejecutarse por primera vez.

Considerando aún un solo hilo (y un solo proceso), toda la "simultaneidad" o "paralelismo" de Twisted proviene del hecho de que en lugar de bloquear E/S de red (y ciertas otras operaciones de bloqueo), Twisted proporciona herramientas para realizar la operación de forma no bloqueante. Esto permite que el programa continúe realizando otro trabajo cuando, de lo contrario, podría haber quedado atascado sin esperar nada para que se complete una operación de bloqueo de E/S (como leer desde o escribir en un socket).

Es posible hacer que las cosas sean "asincrónicas" dividiéndolas en pequeños fragmentos y permitiendo que los controladores de eventos se ejecuten entre estos fragmentos. Este es a veces un enfoque útil, si la transformación no hace que el código sea mucho más difícil de entender y mantener. Twisted proporciona un ayudante para programar estos trozos de trabajo, cooperate. Es útil utilizar esta herramienta ya que puede tomar decisiones de programación basadas en las diferentes fuentes de trabajo y garantizar que haya tiempo restante para las fuentes de eventos de servicio sin una latencia adicional significativa (en otras palabras, más trabajos se agregan a ella). , menos tiempo tendrá cada trabajo, para que el reactor pueda seguir haciendo su trabajo).

Twisted también proporciona varias API para tratar con subprocesos y procesos. Estos pueden ser útiles si no es obvio cómo dividir un trabajo en trozos. Puede usar deferToThread para ejecutar una función (¡seguro para subprocesos!) En un grupo de subprocesos. Convenientemente, esta API devuelve un Deferred que eventualmente disparará con el valor de retorno de la función (o con un Failure si la función genera una excepción).Estos diferidos se parecen a cualquier otro, y en lo que respecta al código que los usa, podría ser el resultado de una llamada como getPage, una función que no utiliza subprocesos adicionales, solo E/S sin bloqueo y controladores de eventos.

Dado que Python no es ideal para ejecutar múltiples subprocesos enlazados a la CPU en un solo proceso, Twisted también proporciona una API no bloqueante para iniciar y comunicarse con procesos secundarios. Puede descargar cálculos a dichos procesos para aprovechar las CPU o núcleos adicionales sin preocuparse de que GIL lo frene, algo que ni la estrategia de fragmentación ni el enfoque de subprocesamiento ofrecen. La API de nivel más bajo para tratar dichos procesos es reactor.spawnProcess. También hay Ampoule, un paquete que administrará un grupo de procesos para usted y proporciona un análogo a deferToThread para procesos, deferToAMPProcess.

Cuestiones relacionadas