Async with Gevent

gevent <http://www.gevent.org/&gt; is recommended for doing asynchronous i/o with Postgresql or MySQL. Reasons I prefer gevent:

  • No need for special-purpose “loop-aware” re-implementations of everything. Third-party libraries using asyncio usually have to re-implement layers and layers of code as well as re-implementing the protocols themselves.
  • Gevent allows you to write your application in normal, clean, idiomatic Python. No need to litter every line with “async”, “await” and other noise. No callbacks, futures, tasks, promises. No cruft.
  • Gevent works with both Python 2 and Python 3.
  • Gevent is Pythonic. Asyncio is an un-pythonic abomination.

Besides monkey-patching socket, no special steps are required if you are using MySQL with a pure Python driver like pymysql or are using mysql-connector in pure-python mode. MySQL drivers written in C will require special configuration which is beyond the scope of this document.

For Postgres and psycopg2, which is a C extension, you can use the following code snippet to register event hooks that will make your connection async:

  1. from gevent.socket import wait_read, wait_write
  2. from psycopg2 import extensions
  3. # Call this function after monkey-patching socket (etc).
  4. def patch_psycopg2():
  5. extensions.set_wait_callback(_psycopg2_gevent_callback)
  6. def _psycopg2_gevent_callback(conn, timeout=None):
  7. while True:
  8. state = conn.poll()
  9. if state == extensions.POLL_OK:
  10. break
  11. elif state == extensions.POLL_READ:
  12. wait_read(conn.fileno(), timeout=timeout)
  13. elif state == extensions.POLL_WRITE:
  14. wait_write(conn.fileno(), timeout=timeout)
  15. else:
  16. raise ValueError('poll() returned unexpected result')

SQLite, because it is embedded in the Python application itself, does not do any socket operations that would be a candidate for non-blocking. Async has no effect one way or the other on SQLite databases.