在BLE设备连接场景中是否需要使用asyncio.Lock()?
要不要启用asyncio.Lock?给你捋清楚
首先明确:必须启用,原因如下:
你忽略了一个关键细节
你以为所有操作都在scan_and_connect()协程里,但disconnected_callback()是BLEak内部触发的——它运行在独立的任务上下文里,和你的scan_and_connect()是异步并发的。也就是说:
- 当设备断开时,
disconnected_callback()会偷偷修改connected_devices集合 - 同时你的
scan_and_connect()可能正在遍历、添加这个集合 - 这俩操作撞在一起,轻则数据乱掉,重则直接抛出「集合迭代时被修改」的RuntimeError
什么时候必须用锁?
只要满足以下任一情况,锁就不能省:
disconnected_callback()里要改connected_devices- 除了
scan_and_connect(),还有其他协程/回调会读写这个集合
正确的锁用法参考
- 先初始化全局锁:
import asyncio connected_devices_lock = asyncio.Lock() - 所有碰
connected_devices的操作,都要套上锁:- 连接设备时加集合:
async with connected_devices_lock: connected_devices.add(device_mac) - 断开回调里删元素:
async def disconnected_callback(client): device_mac = client.address async with connected_devices_lock: if device_mac in connected_devices: connected_devices.remove(device_mac) - 遍历集合时,最好先复制一份(避免持有锁太久阻塞其他操作):
async with connected_devices_lock: # 复制成列表再遍历,锁可以早点释放 current_online = list(connected_devices) for mac in current_online: # 做你的逻辑处理
- 连接设备时加集合:
为啥之前没出问题?
大概率是测试时设备断开次数少,并发冲突的概率低。但这是埋在代码里的隐患,等设备多了、运行时间长了,肯定会炸锅。
内容的提问来源于stack exchange,提问作者user173729
相关产品推荐
相关产品推荐

