The other option is to wrap just the application function, and use
async.coroutines for all else.

I'm sure there are subtleties that I don't understand and will break this stuff.

def async_app(f):

   def _application(environ, start_response):
       status, headers = None, None

       def _start_response(s, h):
           nonlocal status, headers
           status, headers = s, h

       # wrap the function in a asyncio coroutine, then run it as a
Task (which returns an asyncio future)
       co = asyncio.coroutine(f)
       future = asyncio.async(co(environ, _start_response))

       # then do the greenlet dance
       myself = greenlet.getcurrent()
       future.add_done_callback(lambda _: myself.switch()) # goes back
to the suspended call, one line below
       myself.parent.switch()                              # this
suspends the greenlet. goes to the event loop

       # return the result of the function
       start_response(status, headers)
       return future.result()

   return _application

@async_app
def application(environ, start_response):
   start_response('200 OK', [('Content-Type','text/html')])
   response = yield from sleeping()
   return [response]



On 1 February 2015 at 22:20, Damjan Georgievski <[email protected]> wrote:
> Reading about asyncio in uwsgi at
> http://uwsgi-docs.readthedocs.org/en/latest/asyncio.html
>
> I really didn't like the ugly explicit switching, passing the greenlet
> around and the future. So I made this simple decorator that hides that
> away:
>
> def coroutine(f):
>
>    def _f(*args, **kwargs):
>        myself = greenlet.getcurrent()
>        co = asyncio.coroutine(f)
>        future = asyncio.async(co(*args, **kwargs))
>
>        future.add_done_callback(lambda _: myself.switch()) # goes back
> to the suspended call, one line below
>        myself.parent.switch()                              # suspends.
> goes to the event loop
>
>        return future.result()
>
>    return _f
>
> So it takes the wrapped function, wraps it in a asyncio.coroutine,
> sets it for running  as a Task (which returns a future), registers a
> callback on the future to switch back the greenlet, and switches away
> the greenlet. When the greenlet gets switched back to, it gets the
> result of the future and returns that.
>
> @coroutine wrapped functions still need to use 'yield from' of course,
> since they are still asyncio coroutines.
>
> Usage is like this:
>
> @coroutine
> def sleeping():
>    yield from asyncio.sleep(2)
>    return b'test'
>
> def application(environ, start_response):
>    start_response('200 OK', [('Content-Type','text/html')])
>    response = sleeping()
>    return [response]
>
>
> --
> damjan



-- 
damjan
_______________________________________________
uWSGI mailing list
[email protected]
http://lists.unbit.it/cgi-bin/mailman/listinfo/uwsgi

Reply via email to