2014-11-19 28 views
7

In Bash, è possibile eseguire un comando in background aggiungendo &. Come posso farlo in Python?Richieste Python: non attendere il completamento della richiesta

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. 
+0

A differenza di problemi di concorrenza legati alla CPU in Python, questo potrebbe essere possibilmente risolte con un thread separato, o l'uso di 'multiprocessing.dummy' per un pool di thread . –

risposta

12

Io uso multiprocessing.dummy.Pool. Creo un pool di thread singleton a livello di modulo e quindi utilizzo pool.apply_async(requests.get, [params]) per avviare l'attività.

Questo comando mi dà un futuro, che posso aggiungere a un elenco con altri futuri a tempo indeterminato fino a quando non desidero raccogliere tutti o alcuni dei risultati.

multiprocessing.dummy.Pool è, contro tutta la logica e la ragione, un pool di THREAD e non un pool di processi.

Esempio (funziona sia in Python 2 e 3, fino a quando è installato richieste):

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. 

Le richieste saranno eseguiti contemporaneamente, in modo da correre tutti e dieci di queste richieste non dovrebbe richiedere più la più lunga uno. Questa strategia utilizzerà solo un core della CPU, ma questo non dovrebbe essere un problema, perché quasi tutto il tempo sarà trascorso in attesa di I/O.

+1

La tua soluzione sembra interessante, ma anche confusa. Cos'è un futuro? Qual è il livello del modulo? Potresti fornire un esempio funzionante? – octosquidopus

+0

@octosquidopus ha aggiunto l'esempio per rispondere allo –

+0

Il tuo esempio funziona bene, ma non è esattamente quello che sto cercando di fare. Invece di inviare richieste concorrenti, vorrei inviarle una alla volta, ma senza bloccare il resto del codice. Il mio esempio dovrebbe essere ora meno ambiguo. – octosquidopus

1

Secondo il doc, si dovrebbe passare a un'altra libreria:

Blocking Or Non-Blocking?

With the default Transport Adapter in place, Requests does not provide any kind of non-blocking IO. The Response.content property will block until the entire response has been downloaded. If you require more granularity, the streaming features of the library (see Streaming Requests) allow you to retrieve smaller quantities of the response at a time. However, these calls will still block.

If you are concerned about the use of blocking IO, there are lots of projects out there that combine Requests with one of Python’s asynchronicity frameworks.

Two excellent examples are grequests and requests-futures .

+0

Ho provato le richieste-future, ma non riesce a 'csrf = s.cookies ['csrftoken']'. – octosquidopus

1

Se è possibile scrivere il codice da eseguire separatamente in un programma Python separata, here è una possibile soluzione basata su subprocessing .

Altrimenti potresti trovare utile this question e relativa risposta: il trucco è utilizzare la libreria di threading per avviare un thread separato che eseguirà l'attività separata.

Un avvertimento con entrambi gli approcci potrebbe essere il numero di elementi (vale a dire il numero di thread) che devi gestire. Se gli item s in parent sono troppi, è possibile considerare l'interruzione di ogni lotto di elementi fino a quando almeno alcuni thread sono terminati, ma penso che questo tipo di gestione non sia banale.

Per un approccio più sofisticato è possibile utilizzare un approccio basato su attori, non ho utilizzato this library ma penso che in questo caso potrebbe essere d'aiuto.

-1

Ecco un modo hacky per farlo:

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

È possibile perdere una risposta in questo modo spesso. La domanda era su request.post e il suo corpo è anche più fragile con un timeout molto breve di un semplice get. – hynekcer

Problemi correlati