【问题标题】:How to run a coroutine inside a context?如何在上下文中运行协程?
【发布时间】:2020-11-24 14:29:14
【问题描述】:

In the Python docs about Context Vars Context::run 方法被描述为允许在上下文中执行可调用对象,因此可调用对象对上下文执行的更改包含在复制的上下文中。如果你需要执行一个协程怎么办?为了达到同样的行为,你应该怎么做?

就我而言,我想要的是这样的东西来处理可能嵌套事务的事务上下文:

my_ctxvar = ContextVar("my_ctxvar")

async def coro(func, transaction):
    token = my_ctxvar.set(transaction)
    r = await func()
    my_ctxvar.reset(token)  # no real need for this, but why not either
    return r

async def foo():
    ctx = copy_context()
    # simplification to one case here: let's use the current transaction if there is one
    if tx_owner := my_ctxvar not in ctx:
        tx = await create_transaction()
    else:
        tx = my_ctxvar.get()
    
    try:
        r = await ctx.run(coro)  # not actually possible
        if tx_owner:
            await tx.commit()
    except Exception as e:
        if tx_owner:
            await tx.rollback()
        raise from e
    return r

【问题讨论】:

    标签: python async-await python-asyncio coroutine python-contextvars


    【解决方案1】:

    正如我已经指出的herecontext variablesasyncio 原生支持,无需任何额外配置即可使用。 需要注意的是:

    • 当前任务通过await执行的例程共享相同的上下文
    • create_task 生成的新任务在父任务上下文的副本中执行。

    因此,为了在当前上下文的副本中执行协程,可以将其作为任务执行:

    await asyncio.create_task(coro())
    

    小例子:

    import asyncio
    from contextvars import ContextVar
    
    var = ContextVar('var')
    
    
    async def foo():
        await asyncio.sleep(1)
        print(f"var inside foo {var.get()}")
        var.set("ham")  # change copy
    
    
    async def main():
        var.set('spam')
        await asyncio.create_task(foo())
        print(f"var after foo {var.get()}")
    
    
    asyncio.run(main())
    
    var inside foo spam
    var after foo spam
    

    【讨论】:

    • 有没有办法覆盖这种行为?也就是说,手动将上下文传递给子任务,以便子任务可以修改它的父上下文?
    • 据我所知,这是不可能的,您需要使用某种同步或共享变量
    • 我想我知道该怎么做了。我发布了一个单独的问题,我明确表示我想要在任务之间共享上下文的行为:stackoverflow.com/questions/68639982/…
    猜你喜欢
    • 2020-06-29
    • 2019-06-22
    • 2014-12-28
    • 2019-12-18
    • 2023-03-28
    • 1970-01-01
    • 2021-08-24
    • 2018-10-25
    • 1970-01-01
    相关资源
    最近更新 更多