Python Asyncio代码Mac3.7正常,Windows3.8无法触发指定打印语句的排查
问题分析与修复方案
首先,我一眼就注意到这个问题大概率是Python 3.8+ Windows平台下asyncio事件循环的默认切换导致的,结合你的代码细节,具体原因和修复方法如下:
核心原因
- 事件循环兼容性问题:Python 3.8起,Windows系统的asyncio默认事件循环从
SelectorEventLoop换成了ProactorEventLoop,而aiohttp的TCPConnector在Proactor模式下存在调度兼容性问题,导致你的网络请求任务根本没被执行,自然不会走到fetch函数里的打印语句。 - 异常被静默吞掉:你用了
asyncio.gather(*tasks, return_exceptions=True),这个参数会把任务中的所有异常当作返回值处理,而不是抛出,导致你看不到请求失败的具体原因(比如证书加载失败、路径错误等)。 - 冗余的事件循环代码:
loop.create_future()那一行完全多余,虽然不影响功能,但容易混淆逻辑。
Windows环境下的修复方案
1. 强制指定兼容的事件循环
在创建事件循环时,针对Windows平台强制使用SelectorEventLoop,避免Proactor模式的坑:
import sys import asyncio from asyncio import SelectorEventLoop def Initiate(list, folder_week, xmlfile, csvfile): bap = BAPRequest(folder_week, xmlfile, csvfile) # 区分平台设置事件循环 if sys.platform.startswith('win32'): loop = SelectorEventLoop() asyncio.set_event_loop(loop) else: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) # 移除多余的create_future,直接创建任务 future = asyncio.ensure_future(bap.run(list, True)) loop.run_until_complete(future) loop.close()
2. 调试并处理异常
先临时关闭return_exceptions=True,让异常直接抛出,方便你定位问题(比如证书路径是否正确):
# 调试阶段用这个,能直接看到错误 await asyncio.gather(*tasks)
调试完成后,建议加回异常处理,而不是单纯静默吞掉:
results = await asyncio.gather(*tasks, return_exceptions=True) # 遍历结果,打印异常信息 for item_idx, result in enumerate(results): if isinstance(result, Exception): print(f"请求ID {r[item_idx]} 失败: {str(result)}")
3. 修复Windows路径问题
Windows下的路径分隔符是\,直接用./cert/...可能会出问题,改成跨平台的路径写法:
import os # 获取当前脚本所在目录,拼接证书路径 cert_dir = os.path.join(os.path.dirname(__file__), 'cert') cert_path = os.path.join(cert_dir, 'certificate.pem') key_path = os.path.join(cert_dir, 'plainkey.pem') sslcontext.load_cert_chain(cert_path, key_path)
4. 优化ClientSession配置
去掉force_close=True(async with会自动关闭Session),同时确保你的aiohttp是最新版本(避免旧版本的兼容性bug):
async with ClientSession(connector=aiohttp.TCPConnector(ssl=sslcontext)) as session: tasks = [] sem = asyncio.Semaphore(1000) for i in r: task = asyncio.ensure_future(self.bound_fetch(sem, url + str(i), i, session, csv)) tasks.append(task) await asyncio.gather(*tasks, return_exceptions=True) # 不需要手动调用session.close(),async with会自动处理
按照上面的步骤修改后,你的代码应该能在Windows 10 Python 3.8环境下正常执行到fetch函数里的打印语句了。
内容的提问来源于stack exchange,提问作者neelmeg
相关产品推荐
相关产品推荐

