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

Asyncio Lock使用异常求助:多任务互斥执行报错

Asyncio Lock 跨事件循环错误解决

问题场景

需要用Asyncio Lock避免同一设备的异步请求并发执行,测试代码添加Lock后出现RuntimeError: Task got Future attached to a different loop错误。

未加Lock的测试代码(正常并发):

import asyncio

async def method(wait:int):
  print(f"Method with waiting {wait}s starting")
  await asyncio.sleep(wait)
  print(f"Method with waiting {wait}s finished")

async def main():
  task1 = asyncio.create_task(method(2))
  task2 = asyncio.create_task(method(2))
  await task1
  await task2

asyncio.run(main())

输出:

Method with waiting 2s starting
Method with waiting 2s starting
Method with waiting 2s finished
Method with waiting 2s finished

添加Lock后的错误代码:

import asyncio
locker = asyncio.Lock()  # 模块级别初始化Lock

async def method(wait:int):
  async with locker:
    print(f"Method with waiting {wait}s starting")
    await asyncio.sleep(wait)
    print(f"Method with waiting {wait}s finished")

async def main():
  task1 = asyncio.create_task(method(2))
  task2 = asyncio.create_task(method(2))
  await task1
  await task2

asyncio.run(main())

错误输出:

Method with waiting 2s starting
Method with waiting 2s finished
Traceback (most recent call last):
  File "/Users/filip/Desktop/Python/07_Asyncio2.py", line 16, in <module>
    asyncio.run(main())
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/Users/filip/Desktop/Python/07_Asyncio2.py", line 14, in main
    await task2
  File "/Users/filip/Desktop/Python/07_Asyncio2.py", line 5, in method
    async with locker:
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/locks.py", line 14, in __aenter__
    await self.acquire()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/locks.py", line 120, in acquire
    await fut
RuntimeError: Task <Task pending name='Task-3' coro=<method() running at /Users/filip/Desktop/Python/07_Asyncio2.py:5>> got Future <Future pending> attached to a different loop

错误原因

asyncio.Lock()在模块级别初始化时,会自动绑定到当前存在的事件循环。但asyncio.run()函数的特性是:每次调用都会创建一个全新的独立事件循环,执行完毕后关闭该循环。这就导致模块级的Lock绑定的循环和asyncio.run()内部创建的循环不是同一个,任务尝试获取Lock时出现循环不匹配的错误。

解决方案

1. 测试代码修复:在事件循环内创建Lock

将Lock的创建移到main()函数内部,确保Lock和任务处于同一个事件循环中:

import asyncio

async def method(wait:int, locker):
  async with locker:
    print(f"Method with waiting {wait}s starting")
    await asyncio.sleep(wait)
    print(f"Method with waiting {wait}s finished")

async def main():
  locker = asyncio.Lock()  # 在事件循环内部创建Lock
  task1 = asyncio.create_task(method(2, locker))
  task2 = asyncio.create_task(method(2, locker))
  await task1
  await task2

asyncio.run(main())

运行输出(串行执行,符合预期):

Method with waiting 2s starting
Method with waiting 2s finished
Method with waiting 2s starting
Method with waiting 2s finished

2. 实际场景(设备类):在类实例中创建Lock

针对多设备异步通信的场景,为每个设备实例单独创建Lock,确保同一设备的请求串行执行,不同设备的请求可以并发:

import asyncio

class Device:
    def __init__(self, device_id):
        self.device_id = device_id
        self.lock = asyncio.Lock()  # 每个设备实例拥有自己的Lock

    async def send_request(self, wait_time):
        async with self.lock:
            print(f"Device {self.device_id}: Request starting (wait {wait_time}s)")
            await asyncio.sleep(wait_time)  # 模拟设备响应耗时
            print(f"Device {self.device_id}: Request finished")

async def main():
    device1 = Device("Device-A")
    device2 = Device("Device-B")

    # 同一设备的两个请求串行,不同设备的请求并发
    tasks = [
        asyncio.create_task(device1.send_request(2)),
        asyncio.create_task(device1.send_request(2)),
        asyncio.create_task(device2.send_request(1)),
        asyncio.create_task(device2.send_request(1))
    ]
    await asyncio.gather(*tasks)

asyncio.run(main())

运行输出:

Device Device-A: Request starting (wait 2s)
Device Device-B: Request starting (wait 1s)
Device Device-B: Request finished
Device Device-B: Request starting (wait 1s)
Device Device-A: Request finished
Device Device-A: Request starting (wait 2s)
Device Device-B: Request finished
Device Device-A: Request finished

内容的提问来源于stack exchange,提问作者chochf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:35:22