4 ms·
Something like this should work, no? Only run the coroutine if you won the race. D = {} async def maybe_initialize(): global D this_set
by mgraczyk 6y ago
Something like this should work, no? Only run the coroutine if you won the race.
D = {}
async def maybe_initialize():
global D
this_setup = asyncio.ensure_future(one_time_setup())
actual_setup = D.setdefault('initializer', this_setup)
if this_setup is not actual_setup:
this_setup.cancel()
await actual_setup
return
complete example: https://gist.github.com/mgraczyk/e251443bccfe54505e75b6526550c113 https://gist.github.com/mgraczyk/e251443bccfe54505e75b652655...
- sicromoft 6y agoI think something might be off in your mental model of python coroutines. They work via cooperative multitasking. Atomic operations aren't really necessary or relevant in such a system where you are in complete control of all yield points (i.e., calls to `await`). If you read the full blog post, the author solves the problem without setdefault, and without having to cancel any futures.
- mgraczyk 6y agoI understand them quite well, thank you. You don't need setdefault if you only call the initializer from one thread. My code can be made thread safe (as long as you only use one event loop per thread). It's way easier with a single thread. You don't need a lock or atomic operations. initializer = None async def maybe_initialize(): global initializer if initializer is None: initializer = asyncio.ensure_future(one_time_setup()) await initializer return
- jwilk 6y agoThis is the same as the solution from the article, except that: - Chris forgot to declare the variable as global; - Chris used asyncio.create_task() instead of asyncio.ensure_future().
- mgraczyk 6y agoThanks for pointing that out, for some reason I had thought the last implementation also used a lock.
- andreareina 6y agoMaybe it's me not grokking async, but the code seems right to me. `once` is a decorator, so `future` is "instantiated" once per decorated function, which is then accessed as nonlocal in the wrapper. So in the last code sample, every call to `one_time_setup()` is accessing the same `future`.
- benji-york 6y agoSince D is not being rebound, the global declaration is unneeded.
- jwilk 6y ago(Chris has added the global declaration since then.)
- heavenlyblue 6y agoYou have to make it clear you’re speaking of CPU atomics, because whatever atomic operations are trying to solve, for example mainly “read then write” operations - may still easily cause issues within asynchronous code.
- deleted 6y ago[deleted]
- benji-york 6y agoA small point: since you're not rebinding D, you don't need the "global" declaration.