2014-04-25 9 views
3

Windows에서 Python 3.4에서 asyncio 및 aiohttp를 사용하는 https 요청의 경우 2 개의 이벤트 루프를 사용해야합니다. 셸 명령을 실행하는 ProactorEventLoop 및 HTTPS 요청의 기본 이벤트 루프. ProactorEventLoop은 HTTPS 명령에 대해 작동하지 않습니다.Python에서 asyncio 이벤트 루프를 닫으면 예외가 발생합니다.

다음 코드는 새로 만든 기본 이벤트 루프를 사용하고 Windows에서 마지막으로 닫으려고하면 어떻게되는지 보여줍니다.

> Traceback (most recent call last): 
> File "C:\BuildUtilities\p3.4env0\lib\site-packages\aiohttp\connector.py", line 56, in __del__ 
> self.close() 
> File "C:\BuildUtilities\p3.4env0\lib\site-packages\aiohttp\connector.py", line 97, in close 
> transport.close() 
> File "C:\Python34\Lib\asyncio\selector_events.py", line 375, in close 
> self._loop.remove_reader(self._sock_fd) 
> File "C:\Python34\Lib\asyncio\selector_events.py", line 155, in remove_reader 
> key = self._selector.get_key(fd) 
> AttributeError: 'NoneType' object has no attribute 'get_key' 

그것을 언급하는 것은 예외를 제거하고 그 이유를 모르는 : 아래 그림과 같이 내가 마지막에 loop.close를 호출하면 나는 말에 예외를 얻을. 하나 밖에없는

import asyncio 
import aiohttp 

@asyncio.coroutine 
def get_body(url): 
    response = yield from aiohttp.request('GET', url) 
    return (yield from response.read_and_close()) 

#loop = asyncio.ProactorEventLoop() 
loop = asyncio.new_event_loop() 
asyncio.set_event_loop(loop) 

f = asyncio.async(get_body('https://www.google.com')) 
try: 
    loop.run_until_complete(f) 
except Exception as e: 
    print(e) 

if f.result(): 
    print(f.result()) 

loop.close() 

감사합니다, greenaj

답변

2

업데이트는 : 문제는 GitHub의 버전 (0.7.2)에 고정되는 것 같습니다. 오류가 생성되지 않습니다. @danj.py said으로 지정하면 "Get rid of __del__ in connector" commit으로 고정됩니다.


ProactorEventLoop 또는 Windows와 관련이 없습니다. 나는 기본 이벤트 루프와 우분투에 오류를 재현 할 수 있습니다 사용이 올바른 것 때문에

#!/usr/bin/env python3 
import asyncio 
import aiohttp # $ pip install aiohttp 

@asyncio.coroutine 
def get_body(url): 
    response = yield from aiohttp.request('GET', url) 
    return (yield from response.read_and_close()) 

loop = asyncio.get_event_loop() 
body = loop.run_until_complete(get_body('https://stackoverflow.com/q/23283502')) 
print(len(body), type(body), body[:200]) 
loop.close() 

그것은 aiohttp에서 버그가 수 있습니다.

#!/usr/bin/env python3 
import asyncio 
from contextlib import closing 
from urllib.parse import urlsplit 

@asyncio.coroutine 
def get_body(url): 
    # parse url 
    url = urlsplit(url) 
    path = '/' * (not url.path) + url.path + '?' * bool(url.query) + url.query 
    # open connection 
    reader, writer = yield from asyncio.open_connection(
     host=url.hostname, 
     port=url.port or (443 if url.scheme == 'https' else 80), 
     ssl=(url.scheme == 'https')) 
    with closing(writer): 
     # send request 
     writer.write(b'GET ' + path.encode('ascii') + b' HTTP/1.1\r\n' 
        b'Host: ' + url.netloc.encode('ascii') + b'\r\n' 
        b'Connection: close\r\n\r\n') 
     # read headers 
     while True: 
      line = yield from reader.readline() 
      line = line.rstrip(b'\n\r') 
      print(line.decode('latin-1')) 
      if not line: 
       break 
     # read body 
     body = yield from reader.read() 
    return body 

loop = asyncio.get_event_loop() 
body = loop.run_until_complete(get_body('https://stackoverflow.com/q/23283502')) 
print(len(body), type(body), body[:200]) 
loop.close() 

참고 :

는 요청이 aiohttp없이하면 오류가없는 예는 예를 들어, 완전히 동일하지 있으며, 후자는 리디렉션을 수행하지 않습니다.

+1

SelectorEventLoop 닫기가 Windows 7 64 비트에서 더 이상 충돌하지 않는다는 것을 확인했습니다. 'pip install aiohttp --upgrade'는 aiohttp를 0.7.0에서 0.7.2로 업그레이드하면서이 문제를 해결했습니다. 고맙습니다. – greenaj