向运行中的asyncio循环添加摄像头协程导致其他任务停止运行
问题原因
你的runCamera虽然标记为async函数,但里面的OpenCV操作(vid.read()、cv.imshow()、cv.waitKey())全是阻塞式的同步调用,没有任何await异步逻辑。asyncio的事件循环是单线程运行的,一旦执行到runCamera里的阻塞循环,整个事件循环就被卡住了,根本没法切换到greet_every_two_seconds协程执行,所以问候循环直接停摆。
解决方案
针对这种阻塞操作和异步协程共存的场景,有两种实用的解决方式:
方式1:用asyncio线程执行器包装阻塞逻辑
把摄像头的阻塞循环放到线程里运行,让asyncio事件循环可以继续调度其他协程:
import asyncio import cv2 as cv from concurrent.futures import ThreadPoolExecutor async def greet_every_two_seconds(): while True: print('Hello World') await asyncio.sleep(1) def camera_loop(): vid = cv.VideoCapture(0) while True: ret, frame = vid.read() cv.imshow('frame', frame) if cv.waitKey(1) & 0xFF == ord('q'): break vid.release() cv.destroyAllWindows() async def runCamera(): loop = asyncio.get_running_loop() with ThreadPoolExecutor() as executor: await loop.run_in_executor(executor, camera_loop) def main(): loop = asyncio.get_event_loop() asyncio.ensure_future(greet_every_two_seconds()) asyncio.ensure_future(runCamera()) try: loop.run_forever() except KeyboardInterrupt: pass finally: loop.close() if __name__ == "__main__": main()
方式2:直接启动独立线程处理摄像头
如果不想依赖asyncio的线程执行器,也可以直接开一个线程单独跑摄像头逻辑,和asyncio事件循环并行:
import asyncio import cv2 as cv import threading async def greet_every_two_seconds(): while True: print('Hello World') await asyncio.sleep(1) def camera_thread(): vid = cv.VideoCapture(0) while True: ret, frame = vid.read() cv.imshow('frame', frame) if cv.waitKey(1) & 0xFF == ord('q'): break vid.release() cv.destroyAllWindows() def main(): cam_thread = threading.Thread(target=camera_thread) cam_thread.daemon = True cam_thread.start() loop = asyncio.get_event_loop() loop.run_until_complete(greet_every_two_seconds()) if __name__ == "__main__": main()
场景适配说明
对于包含OpenCV摄像头这种阻塞式IO/UI操作的场景,用线程配合asyncio或者直接多线程都是合理选择。asyncio本身更擅长处理网络请求这类原生异步的任务,而对于底层是阻塞实现的操作,放到单独线程里是最直接的破局方式。
内容的提问来源于stack exchange,提问作者ill
相关产品推荐
相关产品推荐

