Closed moriyoshi closed 3 years ago
Does this work at all? The contextvars module is not compatible with greenlets, I believe. Or is it?
CPython's contextvars are per-OS-thread contexts that flow along the call graphs. Semantically speaking, a different context should be created on each greenlet and it's exactly what gevent.contextvars
does. However, what is actually needed in asyncio/greenlet interoperation is to propagate the same lineage of contexts beyond the dispatchers that should reside on the same thread. So, I don't think we have to treat our case specially as long as the context gets restored in each dispatch.
You are oversimplifying the impact contextvars will have on greenlets. Try the following test:
import asyncio
from greenletio import async_, await_
import contextvars
var = contextvars.ContextVar('var')
async def asleep(delay):
var.set(123)
for i in range(10):
await asyncio.sleep(delay)
print('async sleep', var.get())
@async_
def sleep(delay):
var.set(321)
for i in range(10):
await_(asyncio.sleep(delay))
print('greenlet sleep', var.get())
async def main():
await asleep(0.1)
await sleep(0.1)
asyncio.run(main())
The call to asleep()
works great, as this is 100% asyncio based. Then the call to sleep()
fails in a horrible way, even though it does the same. I'm running this on your PR branch.
This patch allows propagating variables in the calling context into greenlets.