Это потому, что сопрограммы могут быть выгружены в будущем? Или это позволяет людям использовать доходность в критическом разделе (что ИМО не следует поощрять)?
Что Python asyncio.Lock() для?
Ответ 1
Вы используете его по той же причине, что и для блокировки в потоковом коде: для защиты критического раздела. asyncio
в первую очередь предназначен для использования в однопоточном коде, но все равно происходит одновременное выполнение, что означает, что вам иногда требуется синхронизация.
Например, рассмотрим функцию, которая извлекает некоторые данные с веб-сервера, а затем кэширует результаты:
@asyncio.coroutine
def get_stuff(url):
if url in cache:
return cache[url]
stuff = yield from aiohttp.request('GET', url)
cache[url] = stuff
return stuff
Теперь предположим, что вы одновременно используете несколько совлокальных подпрограмм, которые потенциально могут использовать возвращаемое значение get_stuff
:
def parse_stuff():
stuff = yield from get_stuff()
# do some parsing
def use_stuff():
stuff = yield from get_stuff()
# use stuff to do something interesting
def do_work():
out = yield from aiohttp.request("www.awebsite.com")
# do some work with out
tasks = [
asyncio.async(parse_stuff()),
asyncio.async(use_stuff()),
asyncio.async(do_work()),
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
Теперь сделайте вид, что выборка данных из url
выполняется медленно. Если одновременно выполняются как parse_stuff
, так и use_stuff
, каждый из них получит полную стоимость перехода по сети, чтобы получить stuff
. Если вы защитите метод с помощью блокировки, вы избегаете этого:
stuff_lock = asyncio.Lock()
def get_stuff(url):
with (yield from stuff_lock):
if url in cache:
return cache[url]
stuff = yield from aiohttp.request('GET', url)
cache[url] = stuff
return stuff
Еще одна вещь, которую следует отметить, состоит в том, что, хотя одна сопрограмма находится внутри get_stuff
, вызывая вызов aiohttp
, а другой ждёт на stuff_lock
, третья сопрограмма, которая не требует вызова get_stuff
вообще, может также выполняться, не подвергая блокировку сопрограммы coroutine на Lock
.
Очевидно, что этот пример немного надуман, но, надеюсь, он дает вам представление о том, почему asyncio.Lock
может быть полезным; он позволяет защитить критический раздел, не блокируя выполнение других сопрограмм, которые не нуждаются в доступе к этому критическому разделу.