Skip to content

Instantly share code, notes, and snippets.

@linw1995
Last active June 6, 2021 06:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save linw1995/a50928ed90d5e8c8c1b9575d7d7fe70c to your computer and use it in GitHub Desktop.
Save linw1995/a50928ed90d5e8c8c1b9575d7d7fe70c to your computer and use it in GitHub Desktop.
Please don't use ContextVar.reset in async_generator.

Please don't use ContextVar.reset in async_generator.

Important rule: Different coroutines own different contexts.

  • The example1.py runs one coroutine with async_generator, the async_generator.__anext__ method runs in same context and thus it works find.
  • The example2.py produces two coroutines with the same async_generator, the async_generator.__anext__ method runs in different contexts and thus it raises an ValueError exception.

Tips for async_generator with ContextVar

  1. don't use reset in async_generator.
  2. need to ensure the context from gen.__anext__() being applied on the procedure of per loop.
async def process_per_loop():
    await gen.__anext__()
    await proceduer()  # do something with same gen.__anext__() context
    asyncio.ensure_future(coro())  # do something with copied gen.__anext__() context
  1. best way is using async-for statement.
async for val in gen:
    await proceduer()  # do something with same gen.__anext__() context
    asyncio.ensure_future(coro())  # do something with copied gen.__anext__() context
import asyncio
from contextvars import ContextVar
var = ContextVar('bar')
async def gen():
token = var.set(1)
yield
var.reset(token)
coro_gen = gen()
await coro_gen.__anext__()
try:
await coro_gen.__anext__()
except StopAsyncIteration:
pass
import asyncio
from contextvars import ContextVar
var = ContextVar('bar')
async def gen():
token = var.set(1)
yield
var.reset(token)
coro_gen = gen()
await asyncio.ensure_future(coro_gen.__anext__())
try:
await coro_gen.__anext__()
except StopAsyncIteration:
pass
# ValueError: <Token var=<ContextVar name='bar' at 0x10ed92130> at 0x10de9c100> was created in a different Context
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment