[openstack-dev] [oslo] Asyncio and oslo.messaging
victor stinner
victor.stinner at enovance.com
Fri Jul 4 23:55:19 UTC 2014
Hi,
I promise a status of my work on Trollius and greenio to Mark, but it's not easy to summarize it because there are still a few pending patches to implement the final greenio executor. There are different parts: asyncio, Trollius, greenio, Olso Messaging.
The design of the asyncio is the PEP 3156 (*) which was accepted and implemented in Python 3.4, released 4 months ago. After the released of Python 3.4, many bugs were fixed in asyncio. The API is stable, it didn't change (and it cannot change because backward compatibility matters in Python, even if the module is still tagged as "provisional" in Python 3.4).
http://legacy.python.org/dev/peps/pep-3156/
Since January, I released regulary new versions of Trollius. Trollius API is the same than the asyncio API, except of the syntax of coroutines:
http://trollius.readthedocs.org/#differences-between-trollius-and-tulip
The next Trollius release will probably be the version 1.0 because I consider that the API is now stable. Last incompatible changes were made to make Trollius look closer to asyncio, and to ease the transition from Trollius to asyncio. I also renamed the module from "asyncio" to "trollius" to support Python 3.4 (which already has an "asyncio" module in the standard library) and to make it more explicit than Trollius coroutines are different than asyncio coroutines.
The greenio project was written for asyncio and it is available on PyPI. greenio only support a few features of asyncio, in short: it only supports executing coroutines. But we only need this feature in Oslo Messaging. I sent a pull request to port greenio to Trollius:
https://github.com/1st1/greenio/pull/5/
The pull request requires a new "task factory": I sent a patch to asyncio for that.
For Oslo Messaging, my change to poll with a timeout has been merged. (I just sent a fix because my change doesn't work with RabbitMQ.) I will work on the greenio executor when other pending patches will be merged. We talked with Mark about this greenio executor. It will be based on the eventlet executor, with a few lines to support Trollius coroutines. We also have to modify the notifier to support to pass an optional "execute" function which executes the endpoint function which may be a coroutine. According to Mark, this change is short and acceptable in Olso Messaging: thanks to the "execute" function, it will be possible to restrict code using greenio in the greenio executor (no need to put greenio nor trollius everywhere in Oslo Messaging).
I listed a lot of projects and pending patches, but I expect that all pieces of the puzzle with be done before the end of the month. We are very close to having a working greenio executor in Oslo Messaging ;-)
Victor
----- Mail original -----
> De: "Mark McLoughlin" <markmc at redhat.com>
> À: openstack-dev at lists.openstack.org
> Envoyé: Jeudi 3 Juillet 2014 17:27:58
> Objet: [openstack-dev] [oslo] Asyncio and oslo.messaging
>
> Hey
>
> This is an attempt to summarize a really useful discussion that Victor,
> Flavio and I have been having today. At the bottom are some background
> links - basically what I have open in my browser right now thinking
> through all of this.
>
> We're attempting to take baby-steps towards moving completely from
> eventlet to asyncio/trollius. The thinking is for Ceilometer to be the
> first victim.
>
> Ceilometer's code is run in response to various I/O events like REST API
> requests, RPC calls, notifications received, etc. We eventually want the
> asyncio event loop to be what schedules Ceilometer's code in response to
> these events. Right now, it is eventlet doing that.
>
> Now, because we're using eventlet, the code that is run in response to
> these events looks like synchronous code that makes a bunch of
> synchronous calls. For example, the code might do some_sync_op() and
> that will cause a context switch to a different greenthread (within the
> same native thread) where we might handle another I/O event (like a REST
> API request) while we're waiting for some_sync_op() to return:
>
> def foo(self):
> result = some_sync_op() # this may yield to another greenlet
> return do_stuff(result)
>
> Eventlet's infamous monkey patching is what make this magic happen.
>
> When we switch to asyncio's event loop, all of this code needs to be
> ported to asyncio's explicitly asynchronous approach. We might do:
>
> @asyncio.coroutine
> def foo(self):
> result = yield from some_async_op(...)
> return do_stuff(result)
>
> or:
>
> @asyncio.coroutine
> def foo(self):
> fut = Future()
> some_async_op(callback=fut.set_result)
> ...
> result = yield from fut
> return do_stuff(result)
>
> Porting from eventlet's implicit async approach to asyncio's explicit
> async API will be seriously time consuming and we need to be able to do
> it piece-by-piece.
>
> The question then becomes what do we need to do in order to port a
> single oslo.messaging RPC endpoint method in Ceilometer to asyncio's
> explicit async approach?
>
> The plan is:
>
> - we stick with eventlet; everything gets monkey patched as normal
>
> - we register the greenio event loop with asyncio - this means that
> e.g. when you schedule an asyncio coroutine, greenio runs it in a
> greenlet using eventlet's event loop
>
> - oslo.messaging will need a new variant of eventlet executor which
> knows how to dispatch an asyncio coroutine. For example:
>
> while True:
> incoming = self.listener.poll()
> method = dispatcher.get_endpoint_method(incoming)
> if asyncio.iscoroutinefunc(method):
> result = method()
> self._greenpool.spawn_n(incoming.reply, result)
> else:
> self._greenpool.spawn_n(method)
>
> it's important that even with a coroutine endpoint method, we send
> the reply in a greenthread so that the dispatch greenthread doesn't
> get blocked if the incoming.reply() call causes a greenlet context
> switch
>
> - when all of ceilometer has been ported over to asyncio coroutines,
> we can stop monkey patching, stop using greenio and switch to the
> asyncio event loop
>
> - when we make this change, we'll want a completely native asyncio
> oslo.messaging executor. Unless the oslo.messaging drivers support
> asyncio themselves, that executor will probably need a separate
> native thread to poll for messages and send replies.
>
> If you're confused, that's normal. We had to take several breaks to get
> even this far because our brains kept getting fried.
>
> HTH,
> Mark.
>
> Victor's excellent docs on asyncio and trollius:
>
> https://docs.python.org/3/library/asyncio.html
> http://trollius.readthedocs.org/
>
> Victor's proposed asyncio executor:
>
> https://review.openstack.org/70948
>
> The case for adopting asyncio in OpenStack:
>
> https://wiki.openstack.org/wiki/Oslo/blueprints/asyncio
>
> A previous email I wrote about an asyncio executor:
>
> http://lists.openstack.org/pipermail/openstack-dev/2013-June/009934.html
>
> The mock-up of an asyncio executor I wrote:
>
> https://github.com/markmc/oslo-incubator/blob/8509b8b/openstack/common/messaging/_executors/impl_tulip.py
>
> My blog post on async I/O and Python:
>
> http://blogs.gnome.org/markmc/2013/06/04/async-io-and-python/
>
> greenio - greelets support for asyncio:
>
> https://github.com/1st1/greenio/
>
>
> _______________________________________________
> OpenStack-dev mailing list
> OpenStack-dev at lists.openstack.org
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
More information about the OpenStack-dev
mailing list