2015-02-09 56 views
3

我有5,00,000個網址。並希望得到每個異步的響應。1個代理的asyncio信號量/多個池鎖 - aiohttp

import aiohttp 
import asyncio  

@asyncio.coroutine 
def worker(url): 
    response = yield from aiohttp.request('GET', url, connector=aiohttp.TCPConnector(share_cookies=True, verify_ssl=False)) 
    body = yield from response.read_and_close() 

    print(url) 

def main(): 
    url_list = [] # lacs of urls, extracting from a file 

    loop = asyncio.get_event_loop() 
    loop.run_until_complete(asyncio.wait([worker(u) for u in url_list])) 

main() 

我希望每次200個連接(併發200),沒有比這更多的是因爲

當我運行此程序的50個URL,它工作正常,即url_list[:50] 但如果我通過整個列表,我得到這個錯誤

aiohttp.errors.ClientOSError: Cannot connect to host www.example.com:443 ssl:True Future/Task exception was never retrieved future: Task() 

可能是頻率太高,服務器拒絕響應後限制?

回答

6

是的,人們可以期望一個服務器在導致過多的流量(不管「流量過多」的定義)後停止響應。

在這種情況下,限制併發請求數(限制它們)的一種方法是使用asyncio.Semaphore,與多線程中使用的類似:您可以創建一個信號量並確保您要調節的操作在做實際工作之前獲得信號量並在之後釋放。

爲了您的方便,asyncio.Semaphore實現了上下文管理器,使其更容易。

大部分基本方法:

CONCURRENT_REQUESTS = 200 


@asyncio.coroutine 
def worker(url, semaphore): 
    # Aquiring/releasing semaphore using context manager. 
    with (yield from semaphore): 
     response = yield from aiohttp.request(
      'GET', 
      url, 
      connector=aiohttp.TCPConnector(share_cookies=True, 
              verify_ssl=False)) 
     body = yield from response.read_and_close() 

     print(url) 


def main(): 
    url_list = [] # lacs of urls, extracting from a file 

    semaphore = asyncio.Semaphore(CONCURRENT_REQUESTS) 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(asyncio.wait([worker(u, semaphore) for u in url_list]))