2015-04-07 20 views
5

Utilizzo Asyncio e Requests per eseguire il benchmark di una serie di richieste HTTP.Asyncio Rende le richieste HTTP più lente?

Per qualche motivo, è leggermente più lento utilizzare Asyncio piuttosto che solo richieste dirette. Qualche idea del perché? Sto usando Asyncio in modo errato?

import asyncio 
import functools 
import requests 
import time 

ts = time.time() 
for i in range(10): 
    @asyncio.coroutine 
    def do_checks(): 
     loop = asyncio.get_event_loop() 
     req = loop.run_in_executor(None, functools.partial(requests.get, "http://google.com", timeout=3)) 
     resp = yield from req 
     print(resp.status_code) 

    loop = asyncio.get_event_loop() 
    loop.run_until_complete(do_checks()) 
te = time.time() 
print("Version A: " + str(te - ts)) 

ts = time.time() 
for i in range(10): 
    r = requests.get("http://google.com", timeout=3) 
    print(r.status_code) 
te = time.time() 

print("Version B: " + str(te - ts)) 

uscita:

Versione A = Asyncio; Versione B = Richieste

200 
200 
200 
200 
200 
200 
200 
200 
200 
200 
Version A: 5.7215821743011475 
200 
200 
200 
200 
200 
200 
200 
200 
200 
200 
Version B: 5.320340156555176 

risposta

12

Stai aspettando che ogni richiesta finisca prima di iniziare quella successiva. Quindi hai il sovraccarico del ciclo degli eventi senza benefici.

Prova questa:

import asyncio 
import functools 
import requests 
import time 

ts = time.time() 
loop = asyncio.get_event_loop() 

@asyncio.coroutine 
def do_checks(): 
    futures = [] 
    for i in range(10): 
     futures.append(loop.run_in_executor(None, functools.partial(requests.get, "http://google.com", timeout=3))) 

    for req in asyncio.as_completed(futures): 
     resp = yield from req 
     print(resp.status_code) 

loop.run_until_complete(do_checks()) 
te = time.time() 
print("Version A: " + str(te - ts)) 

ts = time.time() 
for i in range(10): 
    r = requests.get("http://google.com", timeout=3) 
    print(r.status_code) 
te = time.time() 
print("Version B: " + str(te - ts)) 

Questo è ciò che ottengo quando faccio funzionare:

$ python test.py 
200 
... 
Version A: 0.43438172340393066 
200 
... 
Version B: 1.6541109085083008 

Molto più veloce, ma in realtà questo è solo deponendo le uova le discussioni e di attesa per la libreria HTTP per finire, non hai bisogno di asyncio per farlo.

È possibile effettuare il checkout aiohttp poiché è stato creato per l'uso con asyncio. requests è una libreria favolosa, ma non è stata creata per asyncio.

+0

Grande risposta, che aiuta! Ci sono dei vantaggi nell'avere thread di generazione 'asyncio' invece di farlo direttamente? – okoboko

+2

@okoboko Se vuoi usare 'requests', non c'è davvero bisogno di usare' asyncio', a meno che tu non abbia altri componenti nel tuo progetto che sono effettivamente progettati per l'uso con 'asyncio'. E se questo è il caso, dovresti preferire 'aiohttp' su' requests', a meno che non ti serva una funzionalità di 'requests' che manchi di' aiohttp'. – dano

+2

Una nota con 'loop.run_in_executor' - quando si usa l'esecutore predefinito (passando' None 'come primo argomento), si utilizza un 'concurrent.futures.ThreadPoolExecutor' con cinque thread. Ciò significa che puoi eseguire solo cinque richieste contemporaneamente, il che è piuttosto basso per un carico di lavoro legato all'I/O. Probabilmente otterrai prestazioni migliori se crei il tuo ThreadPoolExecutor con più thread. – dano

6

Solo per completezza, ecco un implementazione molto veloce asyncio

import aiohttp 
import asyncio 
import time 

async def main(n): 
    ts = time.time() 
    session = aiohttp.ClientSession() 
    fs = [session.get('http://google.com') for _ in range(n)] 
    for f in asyncio.as_completed(fs): 
     resp = await f 
     print(resp.status) 
     await resp.release() 
    session.close() 
    te = time.time() 
    print("Aiohttp version: " + str(te - ts)) 

loop = asyncio.get_event_loop() 
loop.run_until_complete(main(10)) 
loop.close() 

Il codice è python 3.5 e versioni successive.

~> python asyncioreq.py 
200 
... 
Aiohttp version: 0.15974688529968262 

speranza che qualcuno può usarlo;)

Problemi correlati