【发布时间】:2020-07-26 21:19:01
【问题描述】:
关于以下SO answer 。为了了解使用 Contextvars 和不使用 Contextvars 之间的区别,我进行了一些更改。
我预计变量myid 在某些时候会损坏,但将范围更改为更高的数字似乎根本没有影响。
import asyncio
import contextvars
# declare context var
request_id = contextvars.ContextVar('Id of request.')
async def some_inner_coroutine(myid):
# get value
print('Processed inner coroutine of myid : {}'.format(myid))
print('Processed inner coroutine of request: {}'.format(request_id.get()))
if myid != request_id.get():
print("ERROR")
async def some_outer_coroutine(req_id):
# set value
request_id.set(req_id)
await some_inner_coroutine(req_id)
# get value
print('Processed outer coroutine of request: {}'.format(request_id.get()))
async def main():
tasks = []
for req_id in range(1, 1250):
tasks.append(asyncio.create_task(some_outer_coroutine(req_id)))
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
结果
Processed inner coroutine of myid : 1
Processed inner coroutine of request: 1
Processed outer coroutine of request: 1
Processed inner coroutine of myid : 2
Processed inner coroutine of request: 2
Processed outer coroutine of request: 2
Processed inner coroutine of myid : 3
Processed inner coroutine of request: 3
Processed outer coroutine of request: 3
Processed inner coroutine of myid : 4
Processed inner coroutine of request: 4
Processed outer coroutine of request: 4
...
...
Processed inner coroutine of myid : 1244
Processed inner coroutine of request: 1244
Processed outer coroutine of request: 1244
Processed inner coroutine of myid : 1245
Processed inner coroutine of request: 1245
Processed outer coroutine of request: 1245
Processed inner coroutine of myid : 1246
Processed inner coroutine of request: 1246
Processed outer coroutine of request: 1246
Processed inner coroutine of myid : 1247
Processed inner coroutine of request: 1247
Processed outer coroutine of request: 1247
Processed inner coroutine of myid : 1248
Processed inner coroutine of request: 1248
Processed outer coroutine of request: 1248
Processed inner coroutine of myid : 1249
Processed inner coroutine of request: 1249
Processed outer coroutine of request: 1249
我应该如何更改才能看到变量 myid 的意外行为?
【问题讨论】:
-
为什么要将它们创建为任务,如果你收集它们,它们会立即开始运行?只做后者
-
我不明白。请您详细说明一下吗?
-
contextvars 不是局部变量的替代品,它们可以正常工作。它们是 global 变量的替代品,在所有任务之间共享。如果
myid是一个全局变量(比如通过上下文管理器设置),那么它将只能保存一个值。使用线程,您可以引入线程局部变量并具有线程局部的“全局”状态。 Contextvars 等价于任务(也支持回调)。 -
所以基本上我的任务在同一个线程中运行并共享相同的上下文变量。如果我有多个线程,那么我会看到上下文变量有多么有用。我说的对吗?
-
没有。 contextvar 的重点是单个 var 在不同的异步任务和类似任务的上下文中具有不同的值,所有这些都在同一个线程上运行。 contextvars 不对多线程有用,因为它们是为明确单线程的异步设计的。
标签: python multithreading python-asyncio python-contextvars