Solicitudes de Python: No espere a que finalice la solicitud

En Bash, es posible ejecutar un comando en segundo plano agregando & . ¿Cómo puedo hacerlo en Python?

 while True: data = raw_input('Enter something: ') requests.post(url, data=data) # Don't wait for it to finish. print('Sending POST request...') # This should appear immediately. 

Yo uso multiprocessing.dummy.Pool . Creo un grupo de subprocesos singleton en el nivel de módulo y luego uso pool.apply_async(requests.get, [params]) para iniciar la tarea.

Este comando me da un futuro, que puedo agregar a una lista con otros futuros indefinidamente hasta que me gustaría recostackr todos o algunos de los resultados.

multiprocessing.dummy.Pool es, contra toda lógica y razón, un conjunto de HILOS y no un conjunto de procesos.

Ejemplo (funciona en Python 2 y 3, siempre que las solicitudes estén instaladas):

 from multiprocessing.dummy import Pool import requests pool = Pool(10) # Creates a pool with ten threads; more threads = more concurrency. # "pool" is a module attribute; you can be sure there will only # be one of them in your application # as modules are cached after initialization. if __name__ == '__main__': futures = [] for x in range(10): futures.append(pool.apply_async(requests.get, ['http://example.com/'])) # futures is now a list of 10 futures. for future in futures: print(future.get()) # For each future, wait until the request is # finished and then print the response object. 

Las solicitudes se ejecutarán al mismo tiempo, por lo que la ejecución de las diez solicitudes no debería llevar más tiempo que la más larga. Esta estrategia solo utilizará un núcleo de CPU, pero eso no debería ser un problema porque casi todo el tiempo se pasará esperando la E / S.

Aquí hay una manera pirata de hacerlo:

 try: requests.get("http://127.0.0.1:8000/test/",timeout=0.0000000001) except requests.exceptions.ReadTimeout: pass 

Según el documento , debes moverte a otra biblioteca:

¿Bloqueo o no locking?

Con el adaptador de transporte predeterminado en su lugar, las solicitudes no proporcionan ningún tipo de E / S sin locking. La propiedad Response.content se bloqueará hasta que se haya descargado la respuesta completa. Si necesita más granularidad, las funciones de transmisión de la biblioteca (consulte Solicitudes de transmisión por secuencias) le permiten recuperar cantidades más pequeñas de la respuesta a la vez. Sin embargo, estas llamadas seguirán bloqueando.

Si le preocupa el uso del locking de E / S, hay muchos proyectos que combinan Solicitudes con uno de los marcos de trabajo asíncrónicos de Python.

Dos ejemplos excelentes son las peticiones verdes y las solicitudes futuras .

Solución elegante de Andrew Gorcester . Además, sin usar futuros, es posible usar los atributos de callback y error_callback (ver documento ) para realizar un procesamiento asíncrono:

 def on_success(r: Response): if r.status_code == 200: print(f'Post succeed: {r}') else: print(f'Post failed: {r}') def on_error(ex: Exception): print(f'Post requests failed: {ex}') pool.apply_async(requests.post, args=['http://server.host'], kwargs={'json': {'key':'value'}, callback=on_success, error_callback=on_error)) 

Si puede escribir el código que se ejecutará por separado en un progtwig Python separado, aquí hay una posible solución basada en el subprocesamiento.

De lo contrario, puede encontrar útil esta pregunta y la respuesta relacionada: el truco consiste en utilizar la biblioteca de subprocesos para iniciar un subproceso separado que ejecutará la tarea separada.

Una advertencia con ambos enfoques podría ser la cantidad de elementos (es decir, la cantidad de subprocesos) que debe administrar. Si los item en el item parent son demasiados, puede considerar detener cada lote de elementos hasta que al menos algunos hilos hayan finalizado, pero creo que este tipo de gestión no es trivial.

Para un enfoque más sofisticado, puede utilizar un enfoque basado en actores, no he usado esta biblioteca por mi cuenta pero creo que podría ayudar en ese caso.