Created
July 8, 2020 04:13
-
-
Save zzzeek/f5ac058e30e192f11160ffb52f5224fa to your computer and use it in GitHub Desktop.
do we need to worry about nesting of greenlet_spawn / await_()? seems like not
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import asyncio | |
| import contextvars | |
| import sys | |
| import greenlet | |
| current_greenlet_context = contextvars.ContextVar("current greenlet context") | |
| def await_(coroutine): | |
| current_greenlet = current_greenlet_context.get() | |
| if current_greenlet is None: | |
| raise Exception( | |
| "not running inside a greenlet right now, " | |
| "can't use await_() function" | |
| ) | |
| return current_greenlet.switch(coroutine) | |
| async def greenlet_spawn(fn, *args): | |
| result_future = asyncio.Future() | |
| def run_greenlet_target(): | |
| result_future.set_result(fn(*args)) | |
| return None | |
| async def run_greenlet(): | |
| gl = greenlet.greenlet(run_greenlet_target) | |
| greenlet_coroutine = gl.switch() | |
| while greenlet_coroutine is not None: | |
| task = asyncio.create_task(greenlet_coroutine) | |
| try: | |
| await task | |
| except: | |
| # this allows an exception to be raised within | |
| # the moderated greenlet so that it can continue | |
| # its expected flow. | |
| greenlet_coroutine = gl.throw(*sys.exc_info()) | |
| else: | |
| greenlet_coroutine = gl.switch(task.result()) | |
| current_greenlet = greenlet.greenlet(run_greenlet) | |
| print("set greenlet context to: %s" % run_greenlet) | |
| current_greenlet_context.set(current_greenlet) | |
| try: | |
| await current_greenlet.switch() | |
| finally: | |
| # make sure the context is what we set it to, testing | |
| # that a nested call has no issue | |
| assert current_greenlet_context.get() is current_greenlet | |
| print("reset greenlet context None from: %s" % run_greenlet) | |
| current_greenlet_context.set(None) | |
| return result_future.result() | |
| async def func1(): | |
| print("func1") | |
| await greenlet_spawn(func2) | |
| def func2(): | |
| print("func2") | |
| await_(func3()) | |
| async def func3(): | |
| print("func3") | |
| await greenlet_spawn(func4) | |
| def func4(): | |
| print("func4") | |
| await_(asyncio.sleep(1)) | |
| asyncio.run(func1()) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
output: