内容简介：A common situation inThe naive “solution” would be to track the initialization state in a variable:The reasoning for
A common situation in asyncio Python programs is asynchronous initialization. Some resource must be initialized exactly once before it can be used, but the initialization itself is asynchronous — such as an asyncpg database. Let’s talk about a couple of solutions.
The naive “solution” would be to track the initialization state in a variable:
initialized = False async def one_time_setup(): "Do not call more than once!" ... async def maybe_initialize(): global initialized if not initialized: await one_time_setup() initialized = True
The reasoning for
is the expectation of calling the
function more than once. However, if it might be called from concurrent
tasks there’s a race condition
. If the second caller arrives while the
first is awaiting
, the function will be called a
Switching the order of the call and the assignment won’t help:
async def maybe_initialize(): global initialized if not initialized: initialized = True await one_time_setup()
Since asyncio is cooperative, the first caller doesn’t give up control
until to other tasks until the
never be called twice. However, the second caller may return before
has completed. What we want is for
to be called exactly once, but for no caller to return until it has
My first thought was to use a mutex lock
. This will protect the
prevent followup callers from progressing too soon. Tasks
is still running will block on the
initialized = False initialized_lock = asyncio.Lock() async def maybe_initialize(): global initialized async with initialized_lock: if not initialized: await one_time_setup() initialized = True
Unfortunately this has a serious downside:
asyncio locks are
associated with the loop
where they were created
. Since the
lock variable is global,
can only be called from
the same loop that loaded the module.
creates a new loop
so it’s incompatible.
# create a loop: always an error asyncio.run(maybe_initialize()) # reuse the loop: maybe an error loop = asyncio.get_event_loop() loop.run_until_complete((maybe_initialize()))
(IMHO, it was a mistake for the asyncio API to include explicit loop objects. It’s a low-level concept that unavoidably leaks through most high-level abstractions.)
A workaround is to create the lock lazily. Thank goodness creating a lock isn’t itself asynchronous!
initialized = False initialized_lock = None async def maybe_initialize(): global initialized, initialized_lock if not initialized_lock: initialized_lock = asyncio.Lock() async with initialized_lock: if not initialized: await one_time_setup() initialized = True
This is better, but
can still only ever be called
from a single loop.
asyncio.run(maybe_initialize()) # ok asyncio.run(maybe_initialize()) # error!
future = None async def maybe_initialize(): if not future: future = asyncio.create_task(one_time_setup()) await future
Awaiting a coroutine more than once is an error, but tasks are future-like objects and can be awaited more than once. At least on CPython, they can also be awaited in other loops! So not only is this simpler, it also solves the loop problem!
asyncio.run(maybe_initialize()) # ok asyncio.run(maybe_initialize()) # still ok
This can be tidied up nicely in a
def once(func): future = None async def once_wrapper(*args, **kwargs): nonlocal future if not future: future = asyncio.create_task(func(*args, **kwargs)) return await future return once_wrapper
No more need for
, just decorate the original
@once async def one_time_setup(): ...
以上所述就是小编给大家介绍的《Exactly-Once Initialization in Asynchronous Python》，希望对大家有所帮助，如果大家有任何疑问请给我留言，小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持！
- Kafka: Exactly-once Semantics
- Apache Flink 结合 Kafka 构建端到端的 Exactly-Once 处理
- 使用 Flink 进行高吞吐，低延迟和 Exactly-Once 语义流处理
- 原理解析 | Apache Flink 结合 Kafka 构建端到端的 Exactly-Once 处理
- Exchange 的 Python 开发包 PyExchange
- Python的SMTP服务器 inbox.py
- Python 的 SSH 实现 AsyncSSH
- Python IP 地址操作库 ipaddr-py
Text Processing in Python
David Mertz / Addison-Wesley Professional / 2003-6-12 / USD 54.99
Text Processing in Python describes techniques for manipulation of text using the Python programming language. At the broadest level, text processing is simply taking textual information and doing som......一起来看看 《Text Processing in Python》 这本书的介绍吧!