2015-04-07 28 views
5

Bir dizi HTTP isteğini karşılaştırmak için Asyncio ve Requests kullanıyorum.Asyncio HTTP Talepleri Daha Yavaş Yapılıyor?

Bazı nedenlerden ötürü, Asyncio'yu sadece düz İsteklerden daha az kullanmak daha yavaştır. Bir fikrin neden? Asyncio'yu yanlış mı kullanıyorum?

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)) 

Çıkış:

Tip A = Asyncio; Versiyon B = Talepler

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 

cevap

12

Bir sonraki baslamadan önce her bir talebin bitmesini bekliyorsunuz. Böylece, etkinlik döngüsünün ek yüküne sahip değilsiniz.

bu deneyin: i çalıştırdığınızda

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)) 

Bu bana seni mi:

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

Çok daha hızlı, ama gerçekten bu sadece konuları yumurtlama ve http kütüphane bitmesini bekliyor, Bunu yapmak için asyncio'a ihtiyacınız yoktur.

asyncio ile kullanım için oluşturulduğu şekilde aiohttp çıkışını kontrol etmek isteyebilirsiniz. requests muhteşem bir kütüphanedir, ancak asyncio için yapılmamıştır.

+0

Büyük cevabı, yardımcı olur! Asyncio'yu doğrudan yapmak yerine işlenen konulara sahip olmanın avantajları var mı? – okoboko

+2

@okoboko Eğer 'request' kullanacaksanız, asyncio'yla kullanmak için tasarlanan projenizde başka bileşenler yoksa,' asyncio' kullanmaya gerek yoktur. Ve eğer durum buysa, 'aiohttp'den eksik olan 'request' özelliklerine ihtiyaç duymadıkça' aiohttp' '' request' seçeneğini tercih etmelisiniz. – dano

+2

'loop.run_in_executor' ile bir not - varsayılan yürütücüyü kullandığınızda (ilk argüman olarak' None'ı geçerek), beş iş parçacığıyla bir 'concurrent.futures.ThreadPoolExecutor' kullanıyorsunuz. Bu, eşzamanlı olarak beş istek çalıştırabileceğiniz anlamına gelir, yani G/Ç bağlı iş yükü için oldukça düşüktür. Kendi ThreadPoolExecutor'ınızı daha fazla iş parçacığıyla oluşturursanız muhtemelen daha iyi bir performans elde edersiniz. – dano

6

Sadece şeyiyle burada

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

kod piton 3.5 ve üstü olan gerçekten hızlı bir asyncio uygulamasıdır.

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

Umut birileri bunu kullanabilirsiniz;)