2014-06-19 19 views
5

Właśnie zacząłem używać asyncio libs z Python3.4 i napisałem mały program, który próbuje jednocześnie pobrać 50 stron jednocześnie. Program wysypuje się po kilkuset żądaniach z wyjątkiem "Zbyt wielu otwartych plików".Połączenia nie są zamykane za pomocą współbieżnych żądań HTTP Python3 pobierających

Myślałem, że moja metoda pobierania zamyka połączenia z wywołaniem metody "response.read_and_close()".

Jakieś pomysły, co się tutaj dzieje? Czy podchodzę do tego problemu we właściwy sposób?

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

Błąd Dostaję jest:

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

To działa dobrze dla mnie. Jakiej wersji "aiohttp" używasz? Mam 0.8.1. – dano

Odpowiedz

2

Ok I w końcu go do pracy.

Okazuje się, że musiałem użyć połączenia TCP, które łączy połączenia.

Więc zrobiłem tej zmiennej:

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

i przekazać go przez każdego żądania GET. Moja nowa procedura pobierania wygląda następująco:

@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, mam problem z tobą.

Wyraźne złącze zdecydowanie może rozwiązać problem.

https://github.com/KeepSafe/aiohttp/pull/79 powinien to naprawić również dla niejawnych konektorów.

Dziękuję bardzo za znalezienie wyciek zasobów w aiohttp

UPD. aiohttp 0.8.2 nie ma problemu.

Powiązane problemy