Re: improving async support in psycopg

Daniele Varrazzo <[email protected]> Wed, 31 Mar 2010 12:29:50 +0100
Newsgroups gmane.comp.python.db.psycopg.devel
Message-ID <[email protected]>
On Wed, Mar 31, 2010 at 1:15 AM, Jan Urbański <[email protected]> wrote:
> On 28/03/10 03:35, Daniele Varrazzo wrote:
>>
>> On Sat, Mar 27, 2010 at 2:40 AM, Jan Urbański<[email protected]>  wrote:
>>
>>> Skimming over the patches I have a question: is it really necessary to
>>> add
>>> the callback feature into the C library? AFAICS the callback is executed
>>> on
>>> asynchronous cursors everytime there is a execute() attempt. Couldn't you
>>> just write a Python psycopg2.extensions.cursor subclass that overrides
>>> execute() by calling that callback?
>>
>> As things are now, execute and callproc being the only methods using
>> async features, this is the case. Probably it will be too extending
>> support to other currently blocking methods (begin/commit/rollback
>> etc).
>
> From the discussion it seems that Federico would prefer to shift the
> responsability of safely using async features to the framerworks instead of
> instrumenting more psycopg methods.
>
> OTOH I saw your post on the gevent mailing list and it indeed would be cool
> if you could change your apps to non-blocking without changing their code,
> by just dropping in the gevent module. I'm not convinced that's fully
> possible, though. I think gevent could provide connection and cursor
> subclasses that would emulate connection.commit() by issuing a COMMIT query
> and waiting (non-blockingly) for it to return. You could probably do the
> same thing for other methods and build up a fully async drop-in replacement
> that you could use with django or whatnot.
>
> I think it makes sense to only expose the raw stuff and let frameworks use
> it the way they see fit.
>
> All that sounds very interesting, please keep posting your results!

Hello, I have been working on the "other way". Couldn't write anything
in the last two days, but what I've done has contributed to clarify
myself things a little bit.

What I've understood is that what I want to do, after all... is not
async support :) In the sense that what I want to do doesn't allow,
for instance, to send 2 async queries and put both them in the same
select() call. Each call is still blocking, and still blocks on its
own. The only difference is that it gives the external environment a
possibility to use their way of blocking. For coroutine frameworks,
this block can yield to another waiting coroutine, enabling a
cooperative switch in the middle of a libpq blocking call. I think it
wouldn't work fine for "normal" system, where there is a single Python
stack (Twisted or an UI event loop): in these systems the call would
simply block.

So I think we are really doing two different things: with your
evolution psycopg will be usable with larger freedom and scheduled to
block whenever the caller decides, at the price of not being usable as
DBAPI adapter anymore, but more as a "low level tool" as described.
With my evolution psycopg would be usable from stackless environments
maintaining compatibility with everything built on top of it, but with
an imposed constraint: the select() is called when a psycopg function
is called, non later at users' will.

My patch is relatively little invasive: it only affects where PQexec
is called, i.e. only pq_execute_command_locked (there are also calls
in conn_setup but can probably be refactored to pass through the above
function) and where PQconnectdb is called. These calls are replaced by
the matching async calls, invoking the "wait hook" in the middle. It
is not very different from what e.g. PQexec does in the libpq (it
calls the async version and then blocks using a poll() or a select()).

My plan at this point is to stop calling what I'm doing "async" :) and
let you build the async path as is best for the frameworks you know
about. What I am really touching is the "sync" code path, adding a
"stackless friendly hook". I've currently implemented the hook call
and the connection, which I think was the trickiest part: as soon as i
can I shall implement the PQexec replacement, refactor the conn_setup
to use it and check that all the tests pass using an user supplied
hook (my target is to keep the full DBAPI semantics).

Thank you very much, have a nice day.

-- Daniele
_______________________________________________
Psycopg mailing list
[email protected]
http://lists.initd.org/mailman/listinfo/psycopg