You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:32:41