Python asyncio.Lock() 有啥用?

Posted

技术标签:

【中文标题】Python asyncio.Lock() 有啥用?【英文标题】:what's Python asyncio.Lock() for?Python asyncio.Lock() 有什么用? 【发布时间】:2014-09-12 01:55:09 【问题描述】:

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

【问题讨论】:

这是一个锁,不确定它与抢占有什么关系,当您尝试获取锁时,您会特别放弃控制权,希望在您持有锁的情况下将其还给您。这是为了让一个协程一次可以进入一个临界区。这一切都在文档中。 我认为您没有仔细阅读官方文档或理解问题。 【参考方案1】:

您使用它的原因与在线程代码中使用锁的原因相同:保护关键部分。 asyncio 主要用于单线程代码,但仍会发生并发执行(任何时候遇到yield 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_stuffuse_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 为何有用;它允许您保护关键部分,而不会阻止其他协同程序运行,而 不需要 需要访问该关键部分。

【讨论】:

感谢您的详细解释。让我总结一下(对于不理解问题的人)。 1) 协程不能被抢占——它们一直运行直到“yield from”将控制权返回给循环。 2) asyncio.Lock() 用于保护调用“yield from”的关键部分——否则不需要使用锁。讨论假设单线程 asyncio 使用模式。 dano - 在这个特定的示例中(请记住,它确实是人为设计的),如果您只是删除 yield from 并发出阻塞 HTTP 请求,您不会获得相同的性能吗?因为在锁定状态下,只有 1 个 get_stuff() 实例会一直在进行中。 (如,实例 B 只能在实例 A 完全完成时启动。) @NickChammas 如果整个应用程序中运行的唯一协程正在等待get_stuff,那么性能将是相当的。但是,如果您有其他协程运行其他不需要锁的方法,那么不;阻塞的 HTTP 请求会阻塞所有其他协程,完全停止您的应用程序,直到它完成。使用asyncio.Lock 允许所有其他协程继续运行。 @SamanthaAtkins 我的回答解释了为什么有时这仍然是必要的。基本上,因为您可以同时运行多个协同程序,您仍然需要同步以防止它们同时进入关键部分。在asyncio 的情况下,关键部分只需要使用yield fromawait 调用锁定是必要的。 @SamanthaAtkins 他们不能并行运行,但可以同时运行。我的回答再次给出了一个用例,其中没有锁定的并发执行会导致意外行为。【参考方案2】:

一个例子是当你只希望一些代码运行一次,却被很多人请求(例如在一个网络应用程序中)

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)

【讨论】:

以上是关于Python asyncio.Lock() 有啥用?的主要内容,如果未能解决你的问题,请参考以下文章

Python中的“断言”有啥用?

Python,枚举类型有啥用? [复制]

bottle.post()python有啥用

Python中“for”循环之后的“else”有啥用? [复制]

python中的set有啥用

用于计算百分位数的纯 python 实现:这里的 lambda 函数有啥用?