Writing an async SQLA application isn't a matter of figuring out implementation details. That's not such a big deal. It's a matter of, what would the end-user application look like ? Sample code ? Best patterns for use ? Since I've never worked with async libraries (other than javascript), I don't have the best answer.
It hardly seems convenient to have entirely new Session objects for every query. I really have no idea what SQLAlchemy would look like supporting async queries in a useful way, but this is not a matter of implementation within SQLA - it seems obvious that we'd need a different Connection class that performs the execute() call differently (since to execute, you need to give a callback who gets the results, right ?). Assuming I'm not totally off base with that, the "you need a callback argument for every execute" pattern would be extracted out into a custom Session subclass and a custom Query subclass, which both support a "callback" calling style. The unit of work probably can't take advantage of this approach, since it deals with executing many statements in order, and would continue to use plain "execute" to do its work - the modified Connection, Session, and Query would continue to implement "synchronous" versions of themselves for this purpose. Similarly, lazyloaders and object refresh calls would still be synchronous, since they occur on attribute access.
That's as deep as my thought goes on this and its all based on hypotheticals since I've never used twisted or greenlets or anything like that. Sorry if I'm totally off on how gevent/greenlets work, the linked documents didn't really make it clear how they work for someone who isn't already familiar.
That's completely fair, the docs leave a lot to be desired. Think of
greenlets as an implementation of cooperative threading. In typical
threading, threads can first of all run in parallel, and the threading
is also preemptive, meaning context switches between threads can
happen at any time. With greenlets, "threads" are run in a single real
OS thread (no parallelism, only multiplexed concurrency), and context
switches between threads happen only voluntarily.
Why is this useful? Because then you can write non-blocking code in a
blocking style. Non-blocking IO is useful for scalable systems
development, but event-driven programming (a la twisted) tends to be
more tedious and less natural than programming with blocking IO. Plus,
most existing code is written against blocking IO, but event-driven
programming makes those difficult to reuse.
So to answer your first question of what things would look like in an
asynchronous world: with cooperative threads like greenlets,
everything would hopefully look identical. Embracing event-driven
style would indeed spell out significant changes to both sqlalchemy
and user code (and that's also not what I'm personally interested in
using).
Upon closer inspection, it seems that changes might not even be
necessary for sqlalchemy, since one can globally set the asynchronous
callback for psycopg to hook directly into gevent.
http://bitbucket.org/dvarrazzo/psycogreen/src/tip/gevent/psyco_gevent.py
--
Yang Zhang
http://yz.mit.edu/