Python中能否将subprocess.Popen调用改为异步执行?
问题根因
你的判断完全准确,当前代码跑成同步模式的核心原因有两个:
- 你用的
subprocess.Popen是同步API,后续调用的whois.communicate()是阻塞式调用,执行这行代码时整个asyncio事件循环会被卡住,无法切换到其他协程执行任务,自然没法实现异步并发 - 现有代码里
queue.task_done()调用位置错误,还没等whois查询执行完成就标记任务处理完毕,会导致队列计数不准
修复方法
不要直接用标准库的同步subprocess模块,改用asyncio内置的异步子进程接口asyncio.create_subprocess_exec,对应的进程通信方法也是异步实现,调用时加await就会主动让出事件循环,不会阻塞其他任务执行。
修复后的完整worker代码如下:
import asyncio async def worker(name, queue): while True: # 从队列获取待查询域名 domain = await queue.get() print(f"\u001b[33m{name}\u001b[0m: {domain}", end="", flush=True) # 异步创建whois子进程,不会阻塞事件循环 whois_proc = await asyncio.create_subprocess_exec( "whois", domain, stdout=asyncio.subprocess.PIPE ) # 异步等待子进程执行完成,读取标准输出 stdout, _ = await whois_proc.communicate() # 整个查询流程走完后再标记任务完成 queue.task_done() print( " " + "\u001b[32mAVAILABLE\u001b[0m" if stdout == b"Domain Not Found\n" else "\u001b[31mUNAVAILABLE\u001b[0m" )
补充说明
需要控制查询并发量时,直接初始化对应数量的worker协程即可,比如要开20个并发查询就启动20个绑定同一个队列的worker任务,所有子进程调用都会异步调度,不会出现同步阻塞的问题。
内容的提问来源于stack exchange,提问作者iruoy
相关产品推荐
相关产品推荐

