Python asyncio context Python asyncio context multithreading multithreading

Python asyncio context


As of Python 3.7 you can make use of contextvars.ContextVar.

In the example below I declared request_id and set the value in some_outer_coroutine, then accessed it in some_inner_coroutine.

import asyncioimport contextvars# declare context varrequest_id = contextvars.ContextVar('Id of request.')async def some_inner_coroutine():    # get value    print('Processed inner coroutine of request: {}'.format(request_id.get()))async def some_outer_coroutine(req_id):    # set value    request_id.set(req_id)    await some_inner_coroutine()    # get value    print('Processed outer coroutine of request: {}'.format(request_id.get()))async def main():    tasks = []    for req_id in range(1, 5):        tasks.append(asyncio.create_task(some_outer_coroutine(req_id)))    await asyncio.gather(*tasks)if __name__ == '__main__':    asyncio.run(main())

Output:

Processed inner coroutine of request: 1Processed outer coroutine of request: 1Processed inner coroutine of request: 2Processed outer coroutine of request: 2Processed inner coroutine of request: 3Processed outer coroutine of request: 3Processed inner coroutine of request: 4Processed outer coroutine of request: 4


There's also https://github.com/azazel75/metapensiero.asyncio.tasklocal, but you must be aware that tasks are often created internally by libraries and also by asyncio using ensure_future(a_coroutine) and there's no actual way to track these new tasks and initialize their locals (maybe with those of the task that they are created from). (an "hack" whould be setting a loop.set_task_factory() function with something that does the job, hoping that all code uses loop.create_task() to create the tasks, which is not always true...)

Another issue is that if some of your code is executed inside a Future callback Task.current_task() function which is used by both the libraries to select the right copy of locals to serve will always return None...