Lock in Asyncio



我试图在Asyncio中使用Lock来防止函数方法()在同一时间运行"多个"。

我的动机:我使用Asyncio库与多个设备进行异步通信。问题是,设备需要一些时间来响应,如果同时向同一设备发送其他请求,则会发生错误。所以我想在类(设备)中建立一个锁来防止这种情况。

这段代码只是在实现到实际代码之前测试概念并理解它的一种非常简单的方法。但是,即使是这个测试代码也不像我期望的那样工作。: D

首先:如果我尝试运行这段代码:

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())

task1开始执行,休眠以便task2启动。然后它们都像这样一个接一个地结束(这是意料之中的):

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

现在我想防止在task1完成之前开始执行task2。我认为最好的办法就是和洛克在一起。所以我修改了代码:

import asyncio
locker = asyncio.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

运行于MacOS, Python版本:3.9.5谢谢你的帮助和提示:)

按照下面的方法修改代码,它就可以工作了:

import asyncio

async def method(wait: int, locker: asyncio.Lock):
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()
await asyncio.gather(method(2, locker), method(2, locker))
if __name__ == '__main__':
asyncio.run(main())
  1. 提供asyncio.Lock作为函数参数
  2. 使用asyncio.gather来同时运行任务,你使用tasks的方式,你根本不需要锁。

主要问题是你的锁和你的协程属于不同的事件循环,所以我把锁移到了另一个地方。

如何检查循环是否不同?在锁声明之后和main函数开始处添加print(id(asyncio.get_event_loop()))行。

最新更新