Re: improving async support in psycopg
Daniele Varrazzo <[email protected]> Sat, 27 Mar 2010 02:21:44 +0000
| Newsgroups | gmane.comp.python.db.psycopg.devel |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Mar 26, 2010 at 7:29 PM, Daniele Varrazzo <[email protected]> wrote: > I've written a first version of the wait_callback idea: code is > available from the 'async' branch of > http://piro.develer.com/psycopg2.git (gitweb: > https://www.develer.com/gitweb/pub?p=users/piro/psycopg2.git;a=summary). > [...] Probably the cb should > have a signature f(conn, cur=None) so that poll() can be invoked on > the right object. I updated the above branch with definition of the wait callback as f(conn, cur=None). Here is a testing script I wrote to check that the async feature works as expected (using gevent). Here, after connect(), the callback is used manually to put the connection in the correct state: as discussed a better interface for this operation can be provided. # make urllib2 coroutine-friendly import gevent import gevent.monkey gevent.monkey.patch_all() import urllib2 # green # have an async connection to play well with gevent import psycopg2 from test_async_gevent import gevent_wait_callback conn = psycopg2.connect("dbname=postgres", async=1) gevent_wait_callback(conn) conn.wait_callback = gevent_wait_callback import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s") logger = logging.getLogger() def download(num, secs): url = "http://localhost:8000/sleep/%d/" % secs for i in range(num): logger.info("download %d start", i) data = urllib2.urlopen(url).read() logger.info("download %d end", i) def fetch(num, secs): cur = conn.cursor() for i in range(num): logger.info("fetch %d start", i) cur.execute("select pg_sleep(%s)", (secs,)) logger.info("fetch %d end", i) # two concurrent tasks: one downloading 2 urls, each taking 3 secs, # the other running 3 queries, each blocking for 2 secs logger.info("making jobs") jobs = [ gevent.spawn(download, 2, 3), gevent.spawn(fetch, 3, 2), ] logger.info("join begin") gevent.joinall(jobs) logger.info("join end") The output of the script is what expected: $ python nonblock.py 2010-03-27 02:01:02,004 making jobs 2010-03-27 02:01:02,022 join begin 2010-03-27 02:01:02,031 download 0 start 2010-03-27 02:01:02,046 fetch 0 start 2010-03-27 02:01:04,106 fetch 0 end 2010-03-27 02:01:04,107 fetch 1 start 2010-03-27 02:01:05,203 download 0 end 2010-03-27 02:01:05,204 download 1 start 2010-03-27 02:01:06,110 fetch 1 end 2010-03-27 02:01:06,111 fetch 2 start 2010-03-27 02:01:08,115 fetch 2 end 2010-03-27 02:01:08,381 download 1 end 2010-03-27 02:01:08,383 join end -- Daniele