46

是不是因为协程将来可能会被抢占?或者它允许人们在关键部分使用产量(不应该鼓励 IMO)?

4

2 回答 2

85

您使用它的原因与在线程代码中使用锁的原因相同:保护关键部分。asyncio主要用于单线程代码,但仍然会发生并发执行(任何时候你点击 ayield fromawait),这意味着有时你需要同步。

例如,考虑一个从 Web 服务器获取一些数据,然后缓存结果的函数:

async def get_stuff(url):
    if url in cache:
        return cache[url]
    stuff = await aiohttp.request('GET', url)
    cache[url] = stuff
    return stuff

现在假设您有多个协同程序同时运行,可能需要使用的返回值get_stuff

async def parse_stuff():
    stuff = await get_stuff("www.example.com/data")
    # do some parsing

async def use_stuff():
    stuff = await get_stuff("www.example.com/data")
    # use stuff to do something interesting

async def do_work():
     out = await aiohttp.request("www.awebsite.com")
     # do some work with out
   

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
    parse_stuff(),
    use_stuff(),
    do_work(),
))

现在,假设从中获取数据url。如果两者parse_stuff同时use_stuff运行,每个都将受到通过网络获取的全部成本的影响stuff。如果你用锁保护方法,你可以避免这种情况:

stuff_lock = asyncio.Lock()

async def get_stuff(url):
    async with stuff_lock:
        if url in cache:
            return cache[url]
        stuff = await aiohttp.request('GET', url)
        cache[url] = stuff
        return stuff

另一件需要注意的事情是,当一个协程在内部get_stuff进行aiohttp调用时,另一个正在等待stuff_lock,第三个根本不需要调用get_stuff的协程也可以运行,而不受Lock.

显然这个例子有点做作,但希望它能让你了解为什么asyncio.Lock有用;它允许您保护关键部分,而不会阻止其他不需要访问该关键部分的协程运行。

于 2014-09-12T02:36:05.310 回答
3

一个例子是,当您只希望某些代码运行一次,却被许多人请求时(例如,在 Web 应用程序中)

async def request_by_many():
    key = False
    lock = asyncio.Lock()
    async with lock:
        if key is False:
            await only_run_once()

async def only_run_once():
    while True:
        if random()>0.5:
            key = True
            break
        await asyncio.sleep(1)
于 2021-05-30T13:42:03.307 回答