Il problema: ho bisogno di inviare molte richieste HTTP a un server. Posso usare solo una connessione (limite del server non negoziabile). Il tempo di risposta del server più la latenza della rete è troppo alto - sono in ritardo.Client HTTP Python con pipelining di richieste
Le richieste in genere non cambiano lo stato del server e non dipendono dalla risposta della richiesta precedente. Quindi la mia idea è semplicemente di inviarli uno sopra l'altro, accodare gli oggetti di risposta e dipendere dal Content-Length: delle risposte in entrata per alimentare le risposte in arrivo all'oggetto di risposta successivo. In altre parole: pipeline le richieste al server.
Ovviamente questo non è del tutto sicuro (qualsiasi risposta senza Content-Length: vuol dire guai), ma non mi interessa, in tal caso posso sempre ritentare qualsiasi richiesta in coda. (Il modo sicuro sarebbe quello di aspettare l'intestazione prima di inviare il bit successivo.)
Quindi, idealmente voglio il seguente codice cliente (che utilizza i ritardi del cliente per imitare la latenza della rete) per l'esecuzione in tre secondi.
Ora per la domanda $ 64000: Esiste una libreria Python che esegue già questa operazione o è necessario eseguire il rollover? Il mio codice usa gevent; Potrei usare Twisted se necessario, ma il pool di connessioni standard di Twisted non supporta le richieste pipeline. Potrei anche scrivere un wrapper per qualche libreria C se necessario, ma preferirei il codice nativo.
#!/usr/bin/python
import gevent.pool
from gevent import sleep
from time import time
from geventhttpclient import HTTPClient
url = 'http://local_server/100k_of_lorem_ipsum.txt'
http = HTTPClient.from_url(url, concurrency=1)
def get_it(http):
print time(),"Queueing request"
response = http.get(url)
print time(),"Expect header data"
# Do something with the header, just to make sure that it has arrived
# (the greenlet should block until then)
assert response.status_code == 200
assert response["content-length"] > 0
for h in response.items():
pass
print time(),"Wait before reading body data"
# Now I can read the body. The library should send at
# least one new HTTP request during this time.
sleep(2)
print time(),"Reading body data"
while response.read(10000):
pass
print time(),"Processing my response"
# The next request should definitely be transmitted NOW.
sleep(1)
print time(),"Done"
# Run parallel requests
pool = gevent.pool.Pool(3)
for i in range(3):
pool.spawn(get_it, http)
pool.join()
http.close()
Nota: come per le librerie C, ho già trovato servo su http://code.google.com/p/serf/. Scrittura di collegamenti Python funzionanti per * quella * libreria purtroppo non è qualcosa per cui sono attualmente pagato. : -/ –
Il tuo codice sembra un po 'come [grequests] (https://github.com/kennethreitz/grequests/blob/master/grequests.py).Hai dato un'occhiata ad esso? Se lo hai, potresti spiegare perché non è una buona idea? (Probabilmente non ho compreso completamente e completamente la domanda) – BorrajaX
grequests è un semplice wrapper asincrono per le richieste, cioè un thread per richiesta, e ognuno è ancora un lockstep send/receive/send-next-bit che usa la propria connessione. Ho bisogno di qualcosa che apra una singola connessione TCP e poi genera un thread che invia le intestazioni delle richieste, e un altro che riceve le risposte e le associa alle "loro" richieste. –