Skip to content

Instantly share code, notes, and snippets.

@KirillMysnik
Last active August 9, 2017 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KirillMysnik/39eb27ae4a3d1057894f1b92dbd28b12 to your computer and use it in GitHub Desktop.
Save KirillMysnik/39eb27ae4a3d1057894f1b92dbd28b12 to your computer and use it in GitHub Desktop.
greenawait.py - await coroutines from greenlet-started functions
def await(coro, *, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
async def new_coro():
return await coro
g, f = greenlet.getcurrent(), loop.create_task(new_coro())
f.add_done_callback(lambda f: g.switch())
g.parent.switch()
return f.result()

What's this?

This is a small replacement for the standard (Python 3.5+) await keyword that you can use when you're inside of a greenlet (and not a Python coroutine).

Why not just use a coroutine?

If you can, of course go with a coroutine. But sometimes it's just not your prerogative. For example, guys at uWSGI say they won't launch your callbacks as a coroutine. They do launch it as a greenlet (--greenlet option) and they do handle asyncio event loop (--asyncio 100 option), though. That's enough for us to implement a replacement for the await keyword that'd swap contexts with the main uWSGI event loop when you call this replacement.

Why would you need coroutines in a webserver anyways? You should respond to browser as soon as possible.

WebSockets

Usage

Given your uWSGI callable is wsgi_callback, you can now utilize the whole power of the Python's asyncio module inside of it:

def wsgi_callback(environ, start_response):
    # You can await any futures/coroutines
    result = await(my_coroutine())

    # Since most of asyncio API are just coroutines, enjoy!

    # Just a regular sleep
    await(asyncio.sleep(2))

    # Usage of the asyncio.wait
    done, pending = await(asyncio.wait(
        [coroutine1(), coroutine2()],
        return_when=asyncio.FIRST_COMPLETE
    ))

    # Don't forget to finally return your response someday
    return []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment