Win10系统下按CTRL+C无法退出Python asyncio服务端脚本问题
问题解决:Windows 10 Python 3.7 asyncio服务无法通过Ctrl+C退出
问题根因
- Windows 10环境下Python 3.7的asyncio默认使用
SelectorEventLoop事件循环,该实现对KeyboardInterrupt信号的捕获存在兼容缺陷,信号触发后无法中断await server.serve_forever()这类阻塞等待操作,导致异常无法抛出到上层捕获逻辑。 - 原代码中
server.wait_closed()为协程对象,未添加await关键字,导致服务关闭逻辑未实际执行,也会引发退出流程卡住。
修复方案
完整修复后代码
import asyncio from asyncio import StreamReader, StreamWriter # 若为类成员方法,保留self参数即可 async def handle_req(reader: StreamReader, writer: StreamWriter): try: data = await reader.read() msg = data.decode() addr = writer.get_extra_info('peername') print(f"Received {msg!r} from {addr!r}") writer.write("Res".encode()) writer.write_eof() await writer.drain() writer.close() except OSError: print("Client endpoint unreachable") async def main(): server = await asyncio.start_server(handle_req, "127.0.0.1", 9000) addr = server.sockets[0].getsockname() print(f'Serving on {addr}') try: async with server: await server.serve_forever() except KeyboardInterrupt: server.close() await server.wait_closed() # 补充await执行服务关闭逻辑 raise if __name__ == '__main__': # Windows下手动指定适配性更好的Proactor事件循环,解决信号捕获问题 asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) try: # 3.7+官方推荐用asyncio.run自动管理事件循环生命周期 asyncio.run(main()) except KeyboardInterrupt: print("服务已正常退出")
核心修改点说明
- 入口处手动设置
WindowsProactorEventLoopPolicy,指定使用适配Windows系统的Proactor事件循环,从根源解决Ctrl+C信号无法被捕获的问题 - 给
server.wait_closed()补充await关键字,保证服务端口释放、资源清理的逻辑正常执行 - 用Python 3.7+官方推荐的
asyncio.run()替代手动管理事件循环的写法,自动处理循环的启动、关闭和资源清理逻辑,避免手动操作引发的遗漏问题
内容的提问来源于stack exchange,提问作者Antonio Santoro
相关产品推荐
相关产品推荐

