两个asyncio任务同时读写单个WebSocket是否存在风险?需用asyncio.Lock吗?
关于WebSocket任务安全与asyncio.Lock的作用
首先得明确:WebSocket对象本身没有设计成支持多个asyncio任务同时读写,这里的「任务不安全」指的是如果多个并发任务直接操作同一个WebSocket实例的读/写方法,可能导致底层的网络数据帧被打乱,出现数据损坏、解析错误的情况。
虽然asyncio是单线程模型,但任务会在await点切换执行。比如你的代码里,read_from_ws在async for message in websocket(本质是反复调用recv)的过程中,可能在某个await点让出事件循环;此时write_to_ws如果刚好执行await websocket.send(message),两个操作的底层网络IO就可能交错,破坏WebSocket的帧结构——毕竟WebSocket是基于TCP的帧协议,需要严格保证读写操作的原子性。
用asyncio.Lock解决的具体做法
asyncio.Lock是异步环境下的互斥锁,它能保证同一时间只有一个任务可以执行被锁包裹的代码块。你需要创建一个锁实例,然后在所有操作WebSocket读/写的地方,用async with lock:把操作包裹起来,确保读写操作不会被并发打断。
修改后的代码示例:
import asyncio import websockets async def read_from_ws(websocket, lock): async with lock: async for message in websocket: print(f"Received message: {message}") async def write_to_ws(websocket, lock): while True: # 注意:input是同步阻塞,会卡住整个事件循环,建议换成异步输入方式 message = input("Enter a message to send: ") async with lock: await websocket.send(message) async def main(): uri = "ws://localhost:12345" ws_lock = asyncio.Lock() async with websockets.connect(uri) as websocket: await asyncio.gather( read_from_ws(websocket, ws_lock), write_to_ws(websocket, ws_lock), ) asyncio.run(main())
额外提醒
你的代码里用了input(),这是同步阻塞调用,会直接卡住整个asyncio事件循环——在input()等待用户输入时,所有其他异步任务(包括WebSocket的读操作)都会暂停。如果要做真正的异步输入,建议用asyncio.Queue配合一个专门读取标准输入的异步任务,比如:
async def async_input(queue): while True: msg = input("Enter a message to send: ") await queue.put(msg) async def write_to_ws(websocket, lock, queue): while True: message = await queue.get() async with lock: await websocket.send(message) # 在main里启动这个任务 async def main(): uri = "ws://localhost:12345" ws_lock = asyncio.Lock() input_queue = asyncio.Queue() async with websockets.connect(uri) as websocket: await asyncio.gather( read_from_ws(websocket, ws_lock), write_to_ws(websocket, ws_lock, input_queue), async_input(input_queue) )
内容的提问来源于stack exchange,提问作者Viet Than
相关产品推荐
相关产品推荐

