Python Asyncio 错误:“OSError:[WinError 6] 句柄无效”和“RuntimeError:事件循环已关闭”[重复]
Posted
技术标签:
【中文标题】Python Asyncio 错误:“OSError:[WinError 6] 句柄无效”和“RuntimeError:事件循环已关闭”[重复]【英文标题】:Python Asyncio errors: "OSError: [WinError 6] The handle is invalid" and "RuntimeError: Event loop is closed" [duplicate] 【发布时间】:2020-06-16 16:02:23 【问题描述】:我在正确使用代码时遇到了一些困难,因为在 VSCode 上调试时我的代码完成执行后出现以下错误:
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000188AB3259D0>
Traceback (most recent call last):
File "c:\users\gam3p\appdata\local\programs\python\python38\lib\asyncio\proactor_events.py", line 116, in __del__
self.close()
File "c:\users\gam3p\appdata\local\programs\python\python38\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "c:\users\gam3p\appdata\local\programs\python\python38\lib\asyncio\base_events.py", line 719, in call_soon
self._check_closed()
File "c:\users\gam3p\appdata\local\programs\python\python38\lib\asyncio\base_events.py", line 508, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
如果我使用命令行运行代码,也会收到以下错误:
Cancelling an overlapped future failed
future: <_OverlappedFuture pending overlapped=<pending, 0x25822633550> cb=[_ProactorReadPipeTransport._loop_reading()]>
Traceback (most recent call last):
File "c:\users\gam3p\appdata\local\programs\python\python38\lib\asyncio\windows_events.py", line 66, in _cancel_overlapped
self._ov.cancel()
OSError: [WinError 6] The handle is invalid
下面的代码是 Reddit 的异步 API 包装器。由于 Reddit 要求机器人被限制在每分钟 60 个请求的速率,我决定实现一个节流循环,在一个单独的线程中处理队列中的请求。
要运行它,您需要create a Reddit app 并使用您的登录凭据以及机器人 ID 和密码。
如果有帮助,我在 Windows 10 上使用 Python 3.8.3 64 位。
import requests
import aiohttp
import asyncio
import threading
from types import SimpleNamespace
from time import time
oauth_url = 'https://oauth.reddit.com/'
base_url = 'https://www.reddit.com/'
agent = 'windows:reddit-async:v0.1 (by /u/UrHyper)'
class Reddit:
def __init__(self, username: str, password: str, app_id: str, app_secret: str):
data = 'grant_type': 'password',
'username': username, 'password': password
auth = requests.auth.HTTPBasicAuth(app_id, app_secret)
response = requests.post(base_url + 'api/v1/access_token',
data=data,
headers='user-agent': agent,
auth=auth)
self.auth = response.json()
if 'error' in self.auth:
msg = f'Failed to authenticate: self.auth["error"]'
if 'message' in self.auth:
msg += ' - ' + self.auth['message']
raise ValueError(msg)
token = 'bearer ' + self.auth['access_token']
self.headers = 'Authorization': token, 'User-Agent': agent
self._rate = 1
self._last_loop_time = 0.0
self._loop = asyncio.new_event_loop()
self._queue = asyncio.Queue(0)
self._end_loop = False
self._loop_thread = threading.Thread(target=self._start_loop_thread)
self._loop_thread.start()
def stop(self):
self._end_loop = True
def __del__(self):
self.stop()
def _start_loop_thread(self):
asyncio.set_event_loop(self._loop)
self._loop.run_until_complete(self._process_queue())
async def _process_queue(self):
while True:
if self._end_loop and self._queue.empty():
await self._queue.join()
break
start_time = time()
if self._last_loop_time < self._rate:
await asyncio.sleep(self._rate - self._last_loop_time)
try:
queue_item = self._queue.get_nowait()
url = queue_item['url']
callback = queue_item['callback']
data = await self._get_data(url)
self._queue.task_done()
callback(data)
except asyncio.QueueEmpty:
pass
finally:
self._last_loop_time = time() - start_time
async def _get_data(self, url):
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=self.headers) as response:
assert response.status == 200
data = await response.json()
data = SimpleNamespace(**data)
return data
async def get_bot(self, callback: callable):
url = oauth_url + 'api/v1/me'
await self._queue.put('url': url, 'callback': callback)
async def get_user(self, user: str, callback: callable):
url = oauth_url + 'user/' + user + '/about'
await self._queue.put('url': url, 'callback': callback)
def callback(data): print(data['name'])
async def main():
reddit = Reddit('', '', '', '')
await reddit.get_bot(lambda bot: print(bot.name))
reddit.stop()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
【问题讨论】:
我遇到了一些类似的问题。尝试添加:asyncio.set_event_loop(asyncio.ProactorEventLoop()) 上面 loop = asyncio.get_event_loop() @GerritGeeraerts 不幸的是这不起作用,我仍然遇到同样的两个错误。 我正在查看我的代码,我还看到了另一行对我有帮助的行。试试这个 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) 而不是 asyncio.set_event_loop(asyncio.ProactorEventLoop()) 我希望这会对你有所帮助 @GerritGeeraerts 解决了这个问题,非常感谢! 【参考方案1】:我在使用 asyncio 时遇到了类似的问题。
从 Python 3.8 开始,他们将 Windows 上的默认事件循环更改为 ProactorEventLoop 而不是 SelectorEventLoop,这存在一些问题。
所以添加
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
上面
loop = asyncio.get_event_loop()
将毫无问题地恢复旧的事件循环。
【讨论】:
哇,这就像魔术!我遇到了这个问题,并且解决了它。非常感谢! 太棒了。我有一个 for in data 循环,有时会显示相同的错误。我在 async def main(): 上方添加了这一行,它似乎有帮助。非常感谢 问题是旧的事件循环不支持像asyncio.subprocess
这样的一些功能以上是关于Python Asyncio 错误:“OSError:[WinError 6] 句柄无效”和“RuntimeError:事件循环已关闭”[重复]的主要内容,如果未能解决你的问题,请参考以下文章
Python Asyncio 错误:“OSError:[WinError 6] 句柄无效”和“RuntimeError:事件循环已关闭”[重复]
Python websockets 服务器和 websockets 客户端在运行这两个任务时使用 asyncio 断言错误
事件的Asyncio NotImplementedError
async 和 asyncio 错误 -- TypeError: 'coroutine' object is not callable