2013-10-11 34 views
17

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() 
+0

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. : -/ –

+0

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

+2

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. –

risposta

-1

E non è una risposta alla tua domanda biblioteca, ma non si poteva usare qualcosa come il selenio e la loro importazione selenium.webdriver.support.ui WebDriverWait di aspettare per le vostre richieste da elaborare per un certo tempo, poi prendendo il tuo prossimo passo, memorizzando la risposta per un uso successivo o inviando la richiesta successiva se non avevi una risposta pertinente?
L'uso di questa interfaccia consentirebbe anche l'uso di un proxy per bypassare (ragionevolmente, a seconda dell'applicazione e delle esigenze) il limite del server (3 o 5 è di aiuto molto più veloce), se non è necessaria l'autenticazione per questa connessione .

-2

Sembra che tu stia eseguendo python2.

Per python3> = 3.5 si potrebbe usare asincrona/await ciclo Vedi asyncio

Inoltre, v'è una biblioteca costruita sulla parte superiore per una migliore, più facile utilizzo chiamato Trio, disponibile su pip.


Un'altra cosa che posso pensare è più thread con serrature. Penserò a come spiegarlo meglio o potrebbe funzionare anche.

+1

Spiegare quale libreria HTTP asincrona è in grado di accodare più di una richiesta su una singola connessione. aiohttp non può farlo. –

+0

l'anser non ha nulla a che fare con il pipelining – MacHala

+0

_aiohttp_ potrebbe aggiungere richieste di pipeline in 'ClientSession': https://github.com/aio-libs/aiohttp/issues/1740 – DurandA

0

Dugong è un client solo HTTP/1.1 che dichiara di supportare il pipelining HTTP/1.1 reale. The tutorial include diversi esempi su come utilizzarlo, incluso uno using threads e un altro using asyncio.

Assicurati di verificare che il server con cui stai comunicando supporti effettivamente il pipelining HTTP/1.1: alcuni server affermano di supportare HTTP/1.1 ma non implementano il pipelining.

Problemi correlati