如何在上下文中运行协同程序



在关于Context Vars的Python文档中,描述了一个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

正如我在这里已经指出的,context 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

相关内容

  • 没有找到相关文章

最新更新