问题
Windows 10 系统下,IPython 解释器内执行某些程序,会导致出现类似如下报错:
Unhandled exception in event loop:
File "C:\Users\secsilm\Anaconda3\lib\asyncio\proactor_events.py", line 768, in _loop_self_reading
f.result() # may raise
File "C:\Users\secsilm\Anaconda3\lib\asyncio\windows_events.py", line 808, in _poll
value = callback(transferred, key, ov)
File "C:\Users\secsilm\Anaconda3\lib\asyncio\windows_events.py", line 457, in finish_recv
raise ConnectionResetError(*exc.args)
Exception [WinError 995] 由于线程退出或应用程序请求,已中止 I/O 操作。
Press ENTER to continue...
复现
Jonathan Slenders 在 issue39010 中提供了一段最小复现代码:
from prompt_toolkit import prompt
while 1:
prompt('>')
然后一直按着 Enter 不放,一会儿就会出现报错了。
原因
根据 IPython 核心开发者 Matthias Bussonnier 在 GitHub 上的回复,大致原因是由于 IPython 所依赖的 prompt_toolkit
刚好在 IPython 7.10 发布之前升级到了 3.x
版本,该版本对 concurrent 进行了优化。但 IPython 还没来得及兼容适配,有一些情况没有被覆盖到。所以将 prompt_toolkit
降到 2.x
应该就好了。
而且,IPython 主要是由他维护的,然而这位核心开发者没有 Windows 机器。。。
解决
对于 Python 3.8 来说,可以直接升级 prompt_toolkit
到最新版本(应该 >= 3.0.18
)来解决这个问题:
pip install -U prompt_toolkit
或者降级到 2.x
:
pip install prompt-toolkit==2.0.10
如果还是不行,则要修改 asyncio
的 proactor_events.py
大约第 769 行处,函数 _loop_self_reading()
,在 f.result()
下面增加代码:
def _loop_self_reading(self, f=None):
try:
if f is not None:
f.result() # may raise
# 增加的代码:START
if self._self_reading_future is not f:
return
# 增加的代码:END
f = self._proactor.recv(self._ssock, 4096)
# 其他代码
而对于 Python 3.9 来说,这个问题应该已经被修复了。
Reference
- ‘Unhandled exception in event loop’ (WinError 995) · Issue #12049 · ipython/ipython
- issue 39010: ProactorEventLoop raises unhandled ConnectionResetError - Python tracker