Re: Async I/O with DBI?
Marc Lehmann <[email protected]>
| Newsgroups | gmane.comp.lang.perl.modules.dbi.sybase.devel |
|---|---|
| Message-ID | <[email protected]> |
On Thu, Jan 15, 2009 at 10:01:32PM +0000, Tim Bunce <[email protected]> wrote: > Marc, what would need to be added to the DBI (or DBD::Gofer) to support > asynchronous use via the Coro module? Method 1, add hooks to DBD::Gofer: Right now, the only sensible way to go is to use DBD::Gofer and add some hooks. Basically, each time you block, e.g. in select or read (or write, if pipelining is to be an option), you need to use some event mechanism to wait. There are many ways to achieve that. Coro has an optional (slowish) wrapper around "select", so instead of doing: print $fh $data; You could do: select .... $fh writable; # slightly messy print $fh $data; Method 2: use unblock or subclass: Another option is to let the user optionally modify the filehandle, e.g. in addition to: nonblock($rfh); one could do: $rfh = $user_callback_to_condition_fh->($rfh) and the user callback could be: sub { Coro::Handle::unblock $_[0] } "unblock" returns something that acts like a perl file handle on the perl level, but allows other coroutines to schedule when blocking on it. Yet another option would be to write a DBD::Gofer::Transport::corostream which would hardcode the above. It probably should be part of the Coro module itself (and was on my todo list). Now that I looked at it, it might be as trivial as subclassing ::stream and overriding start_pipe_command. The only added complexity is that DBD::Gofer suddenly might receive two concurrent requests on the same backend - this would not work without some synchronisation, but a simple "workaround" would be to simply disallow that, i.e. "you must not make concurrent calls on the same gofer object without locking yourself", which, in my experience, is enough. Method 3: AnyEvent::DBI Now, one can already use DBI "asynchronously": AnyEvent::DBI is an event-based DBI interface (in its infancy), which incidentally also supports pipelining. It's use in Coro is trivial (or maybe not, the following is untested :) use Coro; use AnyEvent::DBI; my $dbh = new AnyEvent::DBI "DBI:SQLite:dbname=test.db", "", ""; $dbh->exec ("select * from test", 10, rouse_cb); my ($rows, $rv) = rouse_wait; Method 4: patch each and every dbi driver All the above solutions need a proxy process. It would be vastly faster if we could do it in-process. In fatc, I am researching thread support for dynamic languages for almost a decade now, and my verdict is, it cannot be done, and it makes no sense, unless you do it to make existing interfaces (e.g. sysread or dbi) non-blocking that way. For this, you don't need concurrent access to perl variables. So to get this to work, e.g. in the case of mysql, one needs to add hooks to the driver. Assume DBD::mysql has some mysql_execute function that gets called like this: convert_perl_values_to_mysql_values (); mysql_execute (); convert_mysql_resaults_to_perl_values (); This would need to be changed to: convert_perl_values_to_mysql_values (); release_perl_interpreter_to_do_other_things (); mysql_execute (); lock_perl_interpreter_again (); convert_mysql_resaults_to_perl_values (); This is basically how python, ruby etc. works, which have thread support, which perl has not. To do this, Coro would need to be changed: currently it is a n:m model, i.e. you can have any number of perl (cooperative) threads on any number of C cooperative threads. I have vague plans to change this into a three layer model, there you had any number of perl threads running on a number of C cooperative threads, running in turn on a number of kernel threads. In that case, one could temporarily give control over the curent kernel thread to e.g. libmysql, while the perl interpreter continues to run on another kernel thread. This actually does work already *iff* Coro is configured to use kernel threads, which it has to use on the dreaded broken bsd platforms, but which incurs roughly a 12 times slowdown, so on Linux/Solaris or other working platforms, Coro uses more efficient userspace threads. This last model is one I would prefer, as it combines the strengths of threads (fast inter-thread communicaitons for the sql data) while avoiding its overheads (threads are slow and not well-suited for parallel processing). ============================================================================= This might be a bit longer than you expected, but the idea is, DBI already does work in a fashion (AnyEvent::DBI), and DBD::Gofer could be changed in various ways to make this easier. I even have long-term plans to introduce real kernel threads to perl in the same way as other scripting languages support it, but that's strictly for the future. -- The choice of a Deliantra, the free code+content MORPG -----==- _GNU_ http://www.deliantra.net ----==-- _ generation ---==---(_)__ __ ____ __ Marc Lehmann --==---/ / _ \/ // /\ \/ / [email protected] -=====/_/_//_/\_,_/ /_/\_\