2014-06-19 2 views
5

Je viens de commencer à utiliser les librairies asyncio de Python3.4 et j'ai écrit un petit programme qui tente de récupérer simultanément 50 pages Web à la fois. Le programme explose après quelques centaines de requêtes avec une exception 'Trop de fichiers ouverts'.Les connexions ne se ferment pas avec Python3 asyncio concurrentes HTTP obtiennent des demandes

Je pensais que ma méthode fetch fermait les connexions avec l'appel de méthode 'response.read_and_close()'.

Des idées que se passe-t-il ici? Est-ce que je vais sur ce problème de la bonne façon?

import asyncio 
import aiohttp 

@asyncio.coroutine 
def fetch(url): 
    response = yield from aiohttp.request('GET', url) 
    response = yield from response.read_and_close() 
    return response.decode('utf-8') 

@asyncio.coroutine 
def print_page(url): 
    page = yield from fetch(url) 
    # print(page) 

@asyncio.coroutine 
def process_batch_of_urls(round, urls): 
    print("Round starting: %d" % round) 
    coros = [] 
    for url in urls: 
     coros.append(asyncio.Task(print_page(url))) 
    yield from asyncio.gather(*coros) 
    print("Round finished: %d" % round) 

@asyncio.coroutine 
def process_all(): 
    api_url = 'https://google.com' 
    for i in range(10): 
    urls = [] 
    for url in range(50): 
     urls.append(api_url) 
    yield from process_batch_of_urls(i, urls) 


loop = asyncio.get_event_loop() 
loop.run_until_complete(process_all()) 

L'erreur que je reçois est:

Traceback (most recent call last): 
    File "/usr/local/lib/python3.4/site-packages/aiohttp/client.py", line 106, in request 
    File "/usr/local/lib/python3.4/site-packages/aiohttp/connector.py", line 135, in connect 
    File "/usr/local/lib/python3.4/site-packages/aiohttp/connector.py", line 242, in _create_connection 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 424, in create_connection 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/asyncio/base_events.py", line 392, in create_connection 
    File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/socket.py", line 123, in __init__ 
OSError: [Errno 24] Too many open files 

During handling of the above exception, another exception occurred: 
+0

Cela fonctionne très bien pour moi. Quelle version de 'aiohttp' utilisez-vous? J'ai 0.8.1. – dano

Répondre

2

Ok j'ai finalement eu à travailler.

Il s'avère que j'ai dû utiliser un TCPConnector qui regroupe les connexions.

Je fait cette variable:

connector = aiohttp.TCPConnector(share_cookies=True, loop=loop) 

et passer à travers à chaque demande obtenir. Ma nouvelle routine d'extraction ressemble à ceci:

@asyncio.coroutine 
def fetch(url): 
    data = "" 
    try: 
    yield from asyncio.sleep(1) 
    response = yield from aiohttp.request('GET', url, connector=connector) 
    except Exception as exc: 
     print('...', url, 'has error', repr(str(exc))) 
    else: 
     data = (yield from response.read()).decode('utf-8', 'replace') 
     response.close() 

    return data 
5

Aha, je vous gêne.

Un connecteur explicite peut définitivement résoudre le problème.

https://github.com/KeepSafe/aiohttp/pull/79 devrait aussi le réparer pour les connecteurs implicites.

Merci beaucoup pour trouver la fuite des ressources dans aiohttp

UPD. aiohttp 0.8.2 n'a pas de problème.

Questions connexes