[openstack-dev] [all] Replace eventlet with asyncio

Joshua Harlow harlowja at outlook.com
Tue Feb 17 22:22:09 UTC 2015


I also just put up another proposal to consider:

https://review.openstack.org/#/c/156711/

"""Sew over eventlet + patching with threads"""

It goes along the thread usage case, and seems useful to consider/think 
about (and if it's thrown away, that's ok IMHO, after all thats the 
point of these discussions) when making this kind of analysis and decision.

-Josh

Mike Bayer wrote:
> I’ve spent most of the past week deeply reviewing the asyncio system,
> including that I’ve constructed a comprehensive test suite designed to
> discover exactly what kinds of latencies and/or throughput advantages or
> disadvantages we may see each from: threaded database code, gevent-based
> code using Psycopg2’s asynchronous API, and asyncio using aiopg. I’ve
> written a long blog post describing a bit of background about non-blocking
> IO and its use in Python, and listed out detailed and specific reasons why I
> don’t think asyncio is an appropriate fit for those parts of Openstack that
> are associated with relational databases. We in fact don’t get much benefit
> from eventlet either in this regard, and with the current situation of
> non-eventlet compatible DBAPIs, our continued use of eventlet for
> database-oriented code is hurting Openstack deeply.
>
> My recommendations are that whether or not we use eventlet or asyncio in
> order to receive HTTP connections, the parts of our application that focus
> on querying and updating databases should at least be behind a thread pool.
> I’ve also responded to the notions that asyncio-style programming will lead
> to fewer bugs and faster production of code, and in that area I think there
> are also some misconceptions regarding code that’s designed to deal with
> relational databases.
>
> The blog post is at
> http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/ and
> you’ll find links to the test suite, which is fully runnable, within that
> post.
>
> Victor Stinner<vstinner at redhat.com>  wrote:
>
>> Hi,
>>
>> I wrote a second version of my cross-project specification "Replace eventlet with asyncio". It's now open for review:
>>
>> https://review.openstack.org/#/c/153298/
>>
>> I copied it below if you prefer to read it and/or comment it by email. Sorry, I'm not sure that the spec will be correctly formatted in this email. Use the URL if it's not case.
>>
>> Victor
>>
>> ..
>> This work is licensed under a Creative Commons Attribution 3.0 Unported
>> License.
>>
>> http://creativecommons.org/licenses/by/3.0/legalcode
>>
>> =============================
>> Replace eventlet with asyncio
>> =============================
>>
>> This specification proposes to replace eventlet, implicit async programming,
>> with asyncio, explicit async programming. It should fix eventlet issues,
>> prepare OpenStack for the future (asyncio is now part of the Python language)
>> and may improve overall OpenStack performances. It also makes usage of native
>> threads simpler and more natural.
>>
>> Even if the title contains "asyncio", the spec proposes to use trollius. The
>> name asyncio is used in the spec because it is more well known than trollius,
>> and because trollius is almost the same thing than asyncio.
>>
>> The spec doesn't change OpenStack components running WSGI servers like
>> nova-api.  Compatibility issue between WSGI and asyncio should be solved first.
>>
>> The spec is focused on Oslo Messaging and Ceilometer projects. More OpenStack
>> components may be modified later if the Ceilometer port to asyncio is
>> successful. Ceilometer will be used to find and solve technical issues with
>> asyncio, so the same solutions can be used on other OpenStack components.
>>
>> Blueprint: https://blueprints.launchpad.net/oslo.messaging/+spec/greenio-executor
>>
>> Note: Since Trollius will be used, this spec is unrelated to Python 3. See the
>> `OpenStack Python 3 wiki page<https://wiki.openstack.org/wiki/Python3>`_ to
>> get the status of the port.
>>
>>
>> Problem description
>> ===================
>>
>> OpenStack components are designed to "scale". There are differenet options
>> to support a lot of concurrent requests: implicit asynchronous programming,
>> explicit programming, threads, processes, and combination of these options.
>>
>> In the past, the Nova project used Tornado, then Twisted and it is now using
>> eventlet which also became the defacto standard in OpenStack. The rationale to
>> switch from Twisted to eventlet in Nova can be found in the old `eventlet vs
>> Twisted
>> <https://wiki.openstack.org/wiki/UnifiedServiceArchitecture#eventlet_vs_Twisted>`_
>> article.
>>
>> Eventlet issues
>> ---------------
>>
>> This section only gives some examples of eventlet issues. There are more
>> eventlet issues, but tricky issues are not widely discussed and so not well
>> known. Most interesting issues are issues caused by the design of eventlet,
>> especially the monkey-patching of the Python standard library.
>>
>> Eventlet itself is not really evil. Most issues come from the monkey-patching.
>> The problem is that eventlet is almost always used with monkey-patching in
>> OpenStack.
>>
>> The implementation of the monkey-patching is fragile. It's easy to forget to
>> patch a function or have issues when the standard library is modified. The
>> eventlet port to Python 3 showed how the patcher highly depends on the standard
>> library. A recent eventlet change (v0.16) "turns off __builtin__ monkey
>> patching by default" to fix a tricky race condition: see `eventlet recursion
>> error after RPC timeout
>> <https://bugs.launchpad.net/oslo.messaging/+bug/1369999>`_ and `Second
>> simultaneous read on fileno can be raised on a closed socket #94
>> <https://github.com/eventlet/eventlet/issues/94>`_ issues. Modules implemented
>> in C cannot be fully monkey-patched. Recent example: the `Fix
>> threading.Condition with monkey-patching on Python 3.3 and newer #187
>> <https://github.com/eventlet/eventlet/pull/187>`_ change forces to use the
>> Python implementation of ``threading.RLock``, because the C implementation
>> doesn't use the monkey-patched ``threading.get_ident()`` function to get the
>> thread identifier, but directly a C function.
>>
>> Depending on the import order, modules may or may not be monkey-patched. It's a
>> common trap with eventlet. Monkey-patching makes writing unit tests harder.
>>
>> Some libraries must be modified to support eventlet monkey-patching. Because
>> they have to use original modules, not patched modules, for example. Some
>> patched functions behave differently, which causes issues
>> in applications using them. Example of an OpenStack issue report to the qpid
>> mailing list, `QPID and eventlet.monkey_patch()
>> <https://mail-archives.apache.org/mod_mbox/qpid-dev/201211.mbox/%3C509AC7C4.5030709@redhat.com%3E>`_:
>> "The lock-up occurs because select() returns that the pipe is ready to be read
>> from before anything has been written to the pipe".
>>
>> Since eventlet uses threads, "green" threads, concurrent code must be carefully
>> written to avoid race condition. The section `Explicit async versus implicit
>> async programming`_ below explains this problem.
>>
>> See also drawbacks in the `Eventlet`_ section.
>>
>>
>> Explicit async versus implicit async programming
>> ------------------------------------------------
>>
>> Implicit asynchronous code causes a new kind of race condition issues which are
>> difficult to understand and to fix. It is hard to guess where the scheduler may
>> switch tasks. The source code of a function should be carefully read to check
>> if it may yield control to another coroutine or not. A function of an external
>> module may be modified later to use a blocking function.
>>
>> When asyncio coroutines access data shared with other coroutines, it's possible
>> to avoid locks is most cases.
>>
>> Read the "Ca(sh|che Coherent) Money" section of the `Unyielding
>> <https://glyph.twistedmatrix.com/2014/02/unyielding.html>`_ article (Glyph,
>> February 2014): it explains how a simple log (call to a ``log()``
>> function) can introduce subtle race conditions. It explains how explicit
>> asychronous programming reduces the risk of introducing bugs. With eventlet, if
>> log() becomes asynchronous, you have no reminder that you have to take care of
>> race conditions during a review of the change. With asyncio, you must add
>> "yield from" before log(): it's a nice reminder to say "hey, be careful: your
>> code becomes asynchronous."
>>
>> Disagreements:
>>
>> * Michael Bayer disagrees with Glyph's post. Threads are used virtually
>>   everywhere in software, for decades. They aren't perfect but they are
>>   certainly not as awful as Glyph describes.
>>
>> See also general articles about asynchronous programming:
>>
>> * `Async I/O and Python
>>   <http://blogs.gnome.org/markmc/2013/06/04/async-io-and-python/>`_ by Mark
>>   McLoughlin (June 2013)
>> * `Some Thoughts on Asynchronous Programming
>>   <http://python-notes.curiousefficiency.org/en/latest/pep_ideas/async_programming.html>`_
>>   by Nick Coghlan: A good rundown of the general problem
>>
>>
>> Asyncio and Trollius
>> --------------------
>>
>> asyncio is a new module introduced in the standard library of Python 3.4 (March
>> 2014), it was designed (`PEP 3156
>> <https://www.python.org/dev/peps/pep-3156/>`_) to be a compatible with existing
>> frameworks like Twisted or Tornado. The main difference with Twisted is that
>> coroutines are first class citizen.
>>
>> Advantages:
>>
>> * Explicit asynchronous programming reduces the risk of race conditions: the
>>   developer can identify easily where a function (coroutine) can be
>>   interrupted.
>> * asyncio is maintained by the Python project and rely on existing modules of
>>   the standard library like select, selectors or concurrent.futures. No
>>   need for assembler code (as greenlet).
>> * asyncio has a good design
>>
>> Drawbacks:
>>
>> * asyncio requires Python 3.3 or newer, while OpenStack must support Python
>>   2.7. This issue was solved with the Trollius project, see below.
>> * asyncio is young and may have more bugs than other projects. However the
>>   project is actively developed and its community is active.
>>
>> Trollius has a large test suite of 883 tests. It is tested on Linux, Windows,
>> Mac OS X, FreeBSD, etc. asyncio is tested in a continuous integration
>> infrastruction by buildbots on even more operation systems and various
>> architectures. At the beginning of February 2015, there are 47 open "issues"
>> (bugs, enhancements, feature requests, etc.) and 262 closed issues in Python
>> and Tulip issue trackers. Only one open issue is a bug: `Cancelling wait()
>> after notification leaves Condition in an inconsistent state
>> <http://bugs.python.org/issue22970>`_, but ``asyncio.Condition`` is not widely
>> used.
>>
>> Trollius is released more often than Python: each time a major bug fixed or a
>> new cool feature is added. See the `Trollius changelog
>> <http://trollius.readthedocs.org/changelog.html>`_.
>>
>> See also `Oslo/blueprints/asyncio
>> <https://wiki.openstack.org/wiki/Oslo/blueprints/asyncio>`_.
>>
>>
>> Proposed change
>> ===============
>>
>> First part (done): add support for trollius coroutines
>> ------------------------------------------------------
>>
>> Prepare OpenStack (Oslo Messaging) to support trollius coroutines using
>> ``yield``: explicit asynchronous programming. Eventlet is still supported,
>> used by default, and applications and libraries don't need to be modified at
>> this point.
>>
>> Already done:
>>
>> * Write the trollius project: port asyncio to Python 2
>> * Stabilize trollius API
>> * Add trollius dependency to OpenStack
>> * Write the aioeventlet project to provide the asyncio API on top of eventlet
>> * Stabilize aioeventlet API
>> * Add aioeventlet dependency to OpenStack
>> * Write an aioeventlet executor for Oslo Messaging: code written, change
>>   approved, but not merged yet (need aioeventlet dependency)
>>
>> Second part (to do): rewrite code as trollius coroutines
>> --------------------------------------------------------
>>
>> Switch from implicit asynchronous programming (eventlet using greenthreads) to
>> explicit asynchronous programming (trollius coroutines using ``yield``). Need
>> to modify OpenStack Common Libraries and applications. Modifications can be
>> done step by step, the switch will take more than 6 months.
>>
>> The first application candidate is Ceilometer. The Ceilometer project is young,
>> developers are aware of eventlet issues and like Python 3, and Ceilometer don't
>> rely so much on asynchronous programming: most time is spent into waiting the
>> database anyway.
>>
>> The goal is to port Ceilometer to explicit asynchronous programming during the
>> cycle of OpenStack L.
>>
>> Some applications may continue to use implicit asynchronous programming. For
>> example, nova is probably the most complex part beacuse it is and old project
>> with a lot of legacy code, it has many drivers and the code base is large.
>>
>> To do:
>>
>> * Ceilometer: add trollius dependency and set the trollius event loop policy to
>>   aioeventlet
>> * Ceilometer: change Oslo Messaging executor from "eventlet" to "aioeventlet"
>> * Redesign the service class of Oslo Incubator to support aioeventlet and/or
>>   trollius.  Currently, the class is designed for eventlet. The service class
>>   is instanciated before forking, which requires hacks on eventlet to update
>>   file descriptors.
>> * In Ceilometer and its OpenStack depedencencies: add new functions which
>>   are written with explicit asynchronous programming in mind (ex: trollius
>>   coroutines written with ``yield``). It doesn't make sense to port all Python
>>   libraries to asyncio. Only libraries which are part of performance bottleneck
>>   and doing I/O operations may be ported to asyncio. There is always the
>>   option of running blocking operations in ``loop.run_in_executor()`` to use
>>   a pool of threads.
>> * Rewrite Ceilometer endpoints (RPC methods) as trollius coroutines.
>> * Add a new storage implementation compatible with asyncio. Maybe using
>>   asyncio-mongo?
>>
>> Questions:
>>
>> * The quantity of code which need to be ported to asynchronous programming is
>>   unknown right now.
>> * We should be prepared to see deadlocks. OpenStack was designed for eventlet
>>   which implicitly switch on blocking operations. Critical sections may not be
>>   protected with locks, or not the right kind of lock.
>> * For performances, blocking operations can be executed in threads. OpenStack
>>   code is probably not thread-safe, which means new kinds of race conditions.
>>   But the code executed in threads will be explicitly scheduled to be executed
>>   in a thread (with ``loop.run_in_executor()``), so regressions can be easily
>>   identified.
>> * This part will take a lot of time. We may need to split it into subparts
>>   to have milestones, which is more attractive for developers.
>>
>>
>> Last part (to do): drop eventlet
>> --------------------------------
>>
>> Replace aioeventlet event loop with trollius event loop, drop aioeventlet and
>> drop eventlet at the end.
>>
>> This change will be done on applications one by one. This is no need to port
>> all applications at once. The work will start on Ceilometer, as a follow up
>> of the second part.
>>
>> To do:
>>
>> * Port remaining code to trollius
>> * Write a "trollius" executor for Oslo Messaging
>> * Ceilometer: Add a blocking call to ``loop.run_forever()`` in the ``main()``
>>   function
>> * Ceilometer: Replace "aioeventlet" executor with "trollius" executor
>> * Ceilometer: Use the standard trollius event loop policy
>> * Service class: launcher.wait() must now call ``loop.run_forever()``
>> * Ceilometer: drop the eventlet dependency
>>
>> Optimization, can be done later:
>>
>> * Oslo Messaging: watch directly the underlying file descriptor of sockets,
>>   instead of using a busy loop polling the notifier
>> * Ceilometer: use libraries supporting directly trollius to be able to run
>>   parallel tasks (ex: send multiple requests to a database)
>>
>> Later: replace trollius with asyncio
>> ------------------------------------
>>
>> When a project will be fully Python 3 compatible and OpenStack will be ready to
>> drop Python 2 support, it will be possible to replace trollius with asyncio.
>>
>> Trollius has been designed to be able to easily convert a code base from
>> trollius to asyncio. For example, ``From(obj)`` just returns ``obj``: it's a
>> no-op just to be able to replace the ``yield From(...)`` pattern with ``yield
>> from ...``.
>>
>> Before that, it may be possible to import asyncio instead of trollius, since
>> the API is the same, except of the syntax of coroutines.
>>
>>
>> Alternatives
>> ------------
>>
>> Use directly asyncio, not trollius
>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Trollius is just a "temporary" solution until OpenStack port to Python 3
>> completes and OpenStack decides to drop Python 2 support.
>>
>> Libraries only start to support asyncio, supporting trollius may require extra
>> effort (the effort is not well quantified right now, it may be easier than
>> expected).
>>
>> An alternative is to directly replace eventlet with asyncio, without a
>> temporary step using trollius.
>>
>> The first requirement is to have an application fully Python 3 compatible.
>> Unlikely, eventlet is not yet fully Python 3 compatible. Before eventlet 0.15,
>> released in july 2014, it was not possible to install eventlet on Python 3. So
>> eventlet was a blocker point to port OpenStack components to Python 3. The
>> eventlet port to Python 3 is now almost done, see the `Eventlet`_ section
>> below.
>>
>> The second requirement is to drop Python 2 application. It may not be
>> acceptable right now for the whole OpenStack, but it might be acceptable for
>> some specific applications. RHEL 7 require SCL (Software Collection Library) to
>> get Python 3.3. Debian Wheezy (latest Debian stable) only provides Python 3.2
>> which lacks support of ``yield from`` syntax, required by asyncio.
>>
>> See the `OpenStack Python 3 wiki page
>> <https://wiki.openstack.org/wiki/Python3>`_ to get the status of the port.
>>
>>
>> Eventlet
>> ~~~~~~~~
>>
>> Keep eventlet which is already used.
>>
>> eventlet is based on greenlet which allows to interrupt any function and
>> restart it later, as coroutines but implicitly.
>>
>> Advantages:
>>
>> * Code just looks sequential, no need for extra effort to write async code.
>> * Almost all OpenStack component are already using eventlet.
>>
>> Drawbacks:
>>
>> * See the `Eventlet issues`_ section
>> * The developer cannot know where its function will be interrupted. Basically,
>>   it can be interrupted anywhere. Writing code without race conditions requires
>>   deep knownledge of how Python and eventlet are implemented.
>> * Race conditions are unlikely and so are usually only seen on production.
>>   It's hard to reproduce them. More generally, eventlet is not reliable.
>> * Not compatible with Python 3. This issue is almost fixed: eventlet 0.16
>>   mostly work on Python 3 with monkey-patching. Example of remaining issue:
>>   `Fix threading.Condition with monkey-patching on Python 3.3 and newer
>>   (PR#187)<https://github.com/eventlet/eventlet/pull/187>`_.
>> * In january 2015, Eventlet still doesn't support support IPv6:
>>   `IPv6 support #8<https://github.com/eventlet/eventlet/issues/8>`_
>>   (issue open since January 2013)
>>
>> See also the `Eventlet Best Practices
>> <https://review.openstack.org/#/c/154642>`_ spec.
>>
>>
>> Threads
>> ~~~~~~~
>>
>> Advantages:
>>
>> * Native threads: implemented in the kernel
>> * No requirement of non-blocking sockets or asynchronous functions: just use
>>   any kind of blocking function.
>> * The code is sequential, no callback hell
>>
>> Drawbacks:
>>
>> * Programing with threads (native threads or green threads) is hard because the
>>   code can be interrupted anywhere. It is harder to write "thread-safe" code
>>   (ex: protecting shared data with locks) than to write asyncio code.
>> * CPython (the reference Python implementation) has a Global Interpreter Lock
>>   ("GIL") which reduces the performances of native threads. Only one Python
>>   instruction can be executed at the same time. The GIL is released for I/O
>>   operation. PyPy has a STM project to drop it, but this project is
>>   experimental and it is not yet faster than CPython with GIL.
>>
>> The `C10K program<http://www.kegel.com/c10k.html>`_ showed that asynchronous
>> event-driven is the more efficient than threads to handle concurrent requests,
>> at least for web servers.
>>
>> The `Unyielding<https://glyph.twistedmatrix.com/2014/02/unyielding.html>`_
>> article explains how bad are threads and that threads should be avoided. Native
>> threads should be avoided, but also implicit coroutines like the green threads
>> of eventlet.
>>
>> Disagreements:
>>
>> * Michael Bayer added: "Improving upon GIL has nothing to do with async
>>   programming. Both the GIL, and explicit async, squeeze all operations through
>>   a single CPU serially. The GIL does not block on IO. There are no performance
>>   gains to be had in this regard by async."
>>
>> asyncio uses native threads. For example, by default, resolving a hostname
>> calls the ``getaddrinfo()`` function which is blocking: the function is
>> executed in a thread pool using ``loop.run_in_executor()``. There are
>> asynchronous DNS resolvers available to avoid threads when resolving hostnames.
>> More generally, any blocking function can be executed with
>> ``loop.run_in_executor()`` in asyncio to not block the event loop.
>>
>> David Beazley identified performances issues related to the GIL: see
>> `Understanding the Python GIL<http://www.dabeaz.com/GIL/>`_. Splitting a
>> CPU-bound task into multiple threads may slow down the task instead of making
>> it faster, just because of the GIL. CPU-bound code is the worst case for the
>> GIL. The GIL has been rewritten in Python 3.2 to enhance performances. The
>> optimization will not be backported to Python 2.7.
>>
>>
>> Data model impact
>> -----------------
>>
>> NA
>>
>> REST API impact
>> ---------------
>>
>> NA
>>
>> Security impact
>> ---------------
>>
>> NA
>>
>> Notifications impact
>> --------------------
>>
>> NA
>>
>> Other end user impact
>> ---------------------
>>
>> NA
>>
>> Performance Impact
>> ------------------
>>
>> The performance impact of rewrite coding as trollius coroutines is unknow yet.
>> If there is a overhead of using coroutines, it is expected to be low.
>>
>> We can expect better performances with fully asynchronous clients. See for
>> example `API Hour benchmark
>> <https://github.com/Eyepea/API-Hour#quickndirty-http-benchmarks-on-a-kitchen-table>`_
>> which compares synchronous and asynchronous code for DB requests (using aiopg)
>> and JSON serialization in a web server: asynchronous code can handle much more
>> client requests in 30 seconds.
>>
>> Disagreements:
>>
>> * Michael Bayer is concerned on performance overhead of coroutines. On the
>>   microbenchmark `bench_generator.py
>>   <https://bitbucket.org/haypo/asyncio_staging/src/2f89fbdc7c12bd2541071648018ab9d484d79703/bench_generator.py>`_,
>>   consuming a generator takes 951 ns whereas calling a function takes 228 ns:
>>   consuming a generator is 4.2x slower than calling a function. Basically, the
>>   microbenchmark measures the time to raise an exception (``StopIteration``)
>>   and then to catch it: 723 nanoseconds. A database query typically takes 50 ms
>>   or less.
>>
>>
>> Other deployer impact
>> ---------------------
>>
>> NA
>>
>> Developer impact
>> ----------------
>>
>> To write efficient code, developers have to learn how to write asyncio code,
>> but only on functions which must be asynchronous.
>>
>> Only projects which chose to use asyncio will have to be modified. Other
>> projects are free to continue to use eventlet.
>>
>>
>> Implementation
>> ==============
>>
>> Assignee(s)
>> -----------
>>
>> Assignee is for moving these guidelines through the review process to
>> something that we all agree on. The expectation is that these become
>> review criteria that we can reference and are implemented by a large
>> number of people. Once approved, will also drive collecting volunteers
>> to help fix in multiple projects.
>>
>> Primary assignee:
>>   Victor Stinner<vstinner at redhat.com>
>>
>> Work Items
>> ----------
>>
>> Work items or tasks -- break the feature up into the things that need
>> to be done to implement it. Those parts might end up being done by
>> different people, but we're mostly trying to understand the time-line
>> for implementation.
>>
>> Recently merged changes:
>>
>> * `Add aioeventlet dependency<https://review.openstack.org/#/c/138750/>`_
>> * `Add a new aioeventlet executor<https://review.openstack.org/#/c/136653/>`_:
>>   already approved
>>
>>
>> Dependencies
>> ============
>>
>> The implementation requires a new dependency: the ``aioeventlet`` module. It is
>> already added to global requirements.
>>
>> The ``trollius`` module was already added to global requirements.
>>
>>
>> Testing
>> =======
>>
>> NA
>>
>>
>> Documentation Impact
>> ====================
>>
>> NA
>>
>>
>> Comparison of eventlet and asyncio code
>> =======================================
>>
>> Call a function
>> ---------------
>>
>> eventlet::
>>
>>     evenlet.spawn(func, arg)
>>
>> asyncio::
>>
>>     loop.call_soon(func, arg)
>>
>> Schedule a function in 10 seconds
>> ---------------------------------
>>
>> eventlet::
>>
>>     eventlet.spawn_after(10, func, arg)
>>
>> asyncio::
>>
>>     loop.call_later(10, func, arg)
>>
>> Asynchronous task
>> -----------------
>>
>> eventlet::
>>
>>     def async_multiply(arg):
>>         # interrupt the execution of the current greenthread
>>         eventlet.sleep(1.0)
>>         return arg * 2
>>
>>     def func():
>>         gt = eventlet.spawn(async_multiply, 5)
>>         # block the current greenthread
>>         result = gt.wait()
>>         print("5 * 2 = %s" % result)
>>
>> asyncio::
>>
>>     @asyncio.coroutine
>>     def async_multiply(arg):
>>         # interrupt the execution of the current task
>>         yield from asyncio.sleep(1.0)
>>         return arg * 2
>>
>>     @asyncio.coroutine
>>     def func():
>>         # block the current coroutine
>>         result = yield from async_multiply(5)
>>         print("5 * 2 = %s" % result)
>>
>>
>> asyncio
>> =======
>>
>> Trollius: asyncio port to Python 2
>> ----------------------------------
>>
>> asyncio requires Python 3.3 and newer. asyncio was ported to Python 2 in a new
>> project called `trollius<http://trollius.readthedocs.org/>`_. Changes made in
>> asyncio are merged in trollius, trollius is a branch of the mercurial
>> repository of tulip (asyncio upstream).
>>
>> The major difference between Trollius and Tulip is the syntax of coroutines:
>>
>> ==================  ======================
>> Tulip               Trollius
>> ==================  ======================
>> ``yield from ...``  ``yield From(...)``
>> ``yield from []``   ``yield From(None)``
>> ``return``          ``raise Return()``
>> ``return x``        ``raise Return(x)``
>> ``return x, y``     ``raise Return(x, y)``
>> ==================  ======================
>>
>> It is possible to write code working with trollius and asyncio in the same code
>> base if coroutines are not used, but only callbacks and futures. Some libraries
>> already support asyncio and trollius like AutobahnPython (Websockets and WAMP),
>> Pulsar and Tornado.
>>
>> Another option is to provide functions returning ``Future`` objects, so the
>> caller can decide to use callback using ``fut.add_done_callback(callback)`` or
>> to use coroutines (``yield From(fut)`` for Trollius, or ``yield from fut`` for
>> Tulip). This option is used by the `aiodns<https://github.com/saghul/aiodns>`_
>> project for example.
>>
>> On Python 3.3 and newer, Trollius supports also asyncio coroutines. The
>> trollius module is compatible with asyncio, the opposite is false.
>>
>> Trollius works on Python 2.6-3.5.
>>
>>
>> aioeventlet: asyncio API on top of eventlet
>> -------------------------------------------
>>
>> In OpenStack, eventlet cannot be replaced with asyncio in all projects in a
>> single commit. The OpenStack development is made with small and limited
>> changes. To have a smooth transition, the `aioeventlet project
>> <http://aioeventlet.readthedocs.org/>`_ was written to support the asyncio API
>> on top of eventlet. It makes possible to add support for asyncio coroutines to
>> an existing OpenStack component without having to replace immediatly its
>> ``main()`` function with the blocking call ``loop.run_forever()``.
>>
>> aioeventlet supports waiting for a task from a greenthread (``yield_future()``)
>> and waiting for a greenthread from a task (``wrap_greenthread()``).
>>
>>
>> Databases
>> ---------
>>
>> asyncio database drivers
>> ~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> List of database drivers compatible with asyncio:
>>
>> * MongoDB: `asyncio-mongo<https://bitbucket.org/mrdon/asyncio-mongo>`_
>> * MySQL: `aiomysql<https://github.com/aio-libs/aiomysql>`_ (based on PyMySQL)
>> * PostgreSQL: `aiopg<http://aiopg.readthedocs.org/>`_
>> * PostgreSQL: `psycotulip<https://github.com/fafhrd91/psycotulip>`_ (based on psycopg2)
>> * memcached: `aiomemcache<https://github.com/fafhrd91/aiomemcache>`_
>> * redis: `aioredis<http://aioredis.readthedocs.org/>`_
>> * redis: `asyncio-redis<http://asyncio-redis.readthedocs.org/>`_
>>
>>
>> SQLAchemy
>> ~~~~~~~~~
>>
>> The aiopg project includes a subset of SQLAlchemy which works with asyncio:
>> `aiopg.sa<https://github.com/aio-libs/aiopg/tree/master/aiopg/sa>`_.
>>
>> While most SQLAlchemy functions could be modified to support asyncio, the most
>> important problem is the lazy loading in the ORM. For example, ``user =
>> session.query(User).get(1)`` doesn't run any database query, but the following
>> ``user.addresses`` instruction runs a query.
>>
>> Until SQLAlchemy fully support asyncio, explicit or implicit database queries
>> can be executed in ``loop.run_in_executor()`` to run them in a thread pool, to
>> not block the asyncio event loop.
>>
>> See also the `Performance Impact`_ section: Michael Bayer is concerned by the
>> performance overhead of coroutines. He spent a lot of time to optimize
>> SQLAlchemy.
>>
>>
>> WSGI and HTTP servers
>> =====================
>>
>> The WSGI protocol is synchronous and so incompatible with asyncio. There are
>> "hacks" to support asyncio coroutines with WSGI, like monkey-patching.
>>
>> Using asyncio, there are other efficient ways to write an HTTP server without
>> WSGI: see the HTTP server included in aiohttp for example. The problem is that
>> many OpenStack components rely on the WSGI protocol to support middlewares.
>> Replacing WSGI protocol is not at option right now.
>>
>> For these reasons, this spec doesn't concern OpenStack components running WSGI
>> servers. First, the WSGI protocol should be enhanced or replaced with
>> something having a native support for asynchronous programming.
>>
>> Asynchronous WSGI:
>>
>> * gunicorn: see ``gaiohttp`` worker
>> * `Pulsar: Asynchronous WSGI
>>   <http://pythonhosted.org/pulsar/apps/wsgi/async.html>`_
>> * `uwsgi: uWSGI asynchronous/non-blocking modes
>>   <http://uwsgi-docs.readthedocs.org/en/latest/Async.html>`_
>> * `bottle: Greenlets to the rescue
>>   <http://bottlepy.org/docs/dev/async.html>`_
>> * etc.
>>
>>
>> History
>> =======
>>
>> aioeventlet project (3rd try, patch now merged!):
>>
>> * December 3, 2014: two patches posted to requirements:
>>   `Add aioeventlet dependency<https://review.openstack.org/#/c/138750/>`_
>>   and `Drop greenio dependency<https://review.openstack.org/#/c/138748/>`_.
>> * Novembre 23, 2014: two patches posted to Oslo Messaging:
>>   `Add a new aioeventlet executor<https://review.openstack.org/#/c/136653/>`_
>>   and `Add an optional executor callback to dispatcher
>>   <https://review.openstack.org/#/c/136652/>`_
>> * November 19, 2014: First release of the aioeventlet project
>>
>> OpenStack Kilo Summit, November 3-7, 2014, at Paris:
>>
>> * `Python 3 in Oslo<https://etherpad.openstack.org/p/kilo-oslo-python-3>`_:
>>
>>   * add a new greenio executor to Oslo Messaging
>>   * port eventlet to Python 3 (with monkey-patching)
>>
>> * `What should we do about oslo.messaging?
>>   <https://etherpad.openstack.org/p/kilo-oslo-oslo.messaging>`_: add the new
>>   greenio executor
>>
>> * `Python 3.4 transition<https://etherpad.openstack.org/p/py34-transition>`_
>>
>> greenio executor for Oslo Messaging (second try):
>>
>> * July 29, 2014: Doug Hellmann proposed the blueprint
>>   `A 'greenio' executor for oslo.messaging
>>   <https://blueprints.launchpad.net/oslo.messaging/+spec/greenio-executor>`_,
>>   approved by Mark McLoughlin.
>> * July 24, 2014: `Add greenio dependency<https://review.openstack.org/108637>`_
>>   merged into openstack/requirements
>> * July 22, 2014: Patch `Add a new greenio executor
>>   <https://review.openstack.org/#/c/108652/>`_ proposed to Oslo Messaging
>> * July 21, 2014: Release of greenio 0.6 which is now compatible with Trollius
>> * July 21, 2014: Release of Trollius 1.0
>> * July 14, 2014: Patch `Add a 'greenio' oslo.messaging executor (spec)
>>   <https://review.openstack.org/#/c/104792/>`_ merged into openstack/oslo-specs.
>> * July 7, 2014: Patch `Fix AMQPListener for polling with timeout
>>   <https://review.openstack.org/#/c/104964/>`_ merged into Oslo Messaging
>> * July 2014: greenio executor, `[openstack-dev] [oslo] Asyncio and oslo.messaging
>>   <http://lists.openstack.org/pipermail/openstack-dev/2014-July/039291.html>`_
>>
>> trollius executor for Oslo Messaging (first try):
>>
>> * June 20, 2014: Patch `Add an optional timeout parameter to Listener.poll
>>   <https://review.openstack.org/#/c/71003/>`_ merged into Oslo Messaging
>> * May 28, 2014: Meeting at OpenStack in action with Doug Hellman, Julien
>>   Danjou, Mehdi Abaakouk, Victor Stinner and Christophe to discuss the plan to
>>   port OpenStack to Python 3 and switch from eventlet to asyncio.
>> * April 23, 2014: Patch `Allow trollius 0.2
>>   <https://review.openstack.org/#/c/79901/>`_ merged into
>>   openstack/requirements
>> * March 21, 2014: Patch `Replace ad-hoc coroutines with Trollius coroutines
>>   <https://review.openstack.org/#/c/77925/>`_ proposed to Heat. Heat coroutines
>>   are close to Trollius coroutines. Patch abandonned, need to be rewritten,
>>   maybe with aioeventlet.
>> * February 20, 2014: The full specification of the blueprint was written:
>>   `Oslo/blueprints/asyncio
>>   <https://wiki.openstack.org/wiki/Oslo/blueprints/asyncio>`_
>> * February 8, 2014: Patch `Add a new dependency: trollius
>>   <https://review.openstack.org/#/c/70983/>`_ merged into
>>   openstack/requirements
>> * February 27, 2014: Article `Use the new asyncio module and Trollius in OpenStack
>>   <http://techs.enovance.com/6562/asyncio-openstack-python3>`_ published
>> * February 4, 2014: Patch `Add a new asynchronous executor based on Trollius
>>   <https://review.openstack.org/#/c/70948/>`_ proposed to Oslo Messaging,
>>   but it was abandonned. Running a classic Trollius event loop in a dedicated
>>   thread doesn't fit well into eventlet event loop.
>>
>> First discussion around asyncio and OpenStack:
>>
>> * December 19, 2013: Article `Why should OpenStack move to Python 3 right now?
>>   <http://techs.enovance.com/6521/openstack_python3>`_ published
>> * December 4, 2013: Blueprint `Add a asyncio executor to oslo.messaging
>>   <https://blueprints.launchpad.net/oslo.messaging/+spec/asyncio-executor>`_
>>   proposed by Flavio Percoco and accepted for OpenStack Icehouse by Mark
>>   McLoughlin
>>
>>
>> See also
>> ========
>>
>> Threads on the openstack-dev mailing list:
>>
>> * `[oslo] Progress of the port to Python 3
>>   <http://lists.openstack.org/pipermail/openstack-dev/2015-January/053846.html>`_
>>   (Victor Stinner, Jan 6 2015)
>>
>> * `[oslo] Add a new aiogreen executor for Oslo Messaging
>>   <http://lists.openstack.org/pipermail/openstack-dev/2014-November/051337.html>`_
>>   (Victor Stinner, Nov 23 2014)
>>
>> * `[oslo] Asyncio and oslo.messaging
>>   <http://lists.openstack.org/pipermail/openstack-dev/2014-July/039291.html>`_
>>   (Mark McLoughlin, Jul 3 2014)
>>
>>   * `SQLAlchemy and asynchronous programming
>>     <http://lists.openstack.org/pipermail/openstack-dev/2014-July/039480.html>`_
>>     by Mike Bayer (author and maintainer of SQLAlchemy)
>>
>> * `[Solum][Oslo] Next Release of oslo.messaging?
>>   <http://lists.openstack.org/pipermail/openstack-dev/2014-March/030304.html>`_
>>   (Victor Stinner, Mar 18 2014)
>>
>> * `[solum] async / threading for python 2 and 3
>>   <http://lists.openstack.org/pipermail/openstack-dev/2014-February/027685.html>`_
>>   (Victor Stinner, Feb 20 2014)
>>
>> * `Asynchrounous programming: replace eventlet with asyncio
>>   <http://lists.openstack.org/pipermail/openstack-dev/2014-February/026237.html>`_
>>   (Victor Stinner, Feb 4 2014)
>>
>> __________________________________________________________________________
>> OpenStack Development Mailing List (not for usage questions)
>> Unsubscribe: OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
>> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
> __________________________________________________________________________
> OpenStack Development Mailing List (not for usage questions)
> Unsubscribe: OpenStack-dev-request at lists.openstack.org?subject:unsubscribe
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev



More information about the OpenStack-dev mailing list