--- Coro/Coro.pm 2009/07/22 03:02:07 1.262 +++ Coro/Coro.pm 2010/12/07 17:13:43 1.281 @@ -42,14 +42,14 @@ thread models. Unlike the so-called "Perl threads" (which are not actually real threads -but only the windows process emulation ported to unix, and as such act -as processes), Coro provides a full shared address space, which makes -communication between threads very easy. And Coro's threads are fast, -too: disabling the Windows process emulation code in your perl and using -Coro can easily result in a two to four times speed increase for your -programs. A parallel matrix multiplication benchmark runs over 300 times -faster on a single core than perl's pseudo-threads on a quad core using -all four cores. +but only the windows process emulation (see section of same name for more +details) ported to unix, and as such act as processes), Coro provides +a full shared address space, which makes communication between threads +very easy. And Coro's threads are fast, too: disabling the Windows +process emulation code in your perl and using Coro can easily result in +a two to four times speed increase for your programs. A parallel matrix +multiplication benchmark runs over 300 times faster on a single core than +perl's pseudo-threads on a quad core using all four cores. Coro achieves that by supporting multiple running interpreters that share data, which is especially useful to code pseudo-parallel processes and @@ -69,8 +69,9 @@ package Coro; -use strict qw(vars subs); -no warnings "uninitialized"; +use common::sense; + +use Carp (); use Guard (); @@ -82,9 +83,9 @@ our $main; # main coro our $current; # current coro -our $VERSION = 5.161; +our $VERSION = 5.25; -our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub); +our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub rouse_cb rouse_wait); our %EXPORT_TAGS = ( prio => [qw(PRIO_MAX PRIO_HIGH PRIO_NORMAL PRIO_LOW PRIO_IDLE PRIO_MIN)], ); @@ -125,38 +126,25 @@ usually better to rely on L or L, as this is pretty low-level functionality. -This variable stores either a Coro object or a callback. +This variable stores a Coro object that is put into the ready queue when +there are no other ready threads (without invoking any ready hooks). -If it is a callback, the it is called whenever the scheduler finds no -ready coros to run. The default implementation prints "FATAL: -deadlock detected" and exits, because the program has no other way to -continue. - -If it is a coro object, then this object will be readied (without -invoking any ready hooks, however) when the scheduler finds no other ready -coros to run. +The default implementation dies with "FATAL: deadlock detected.", followed +by a thread listing, because the program has no other way to continue. This hook is overwritten by modules such as C and C to wait on an external event that hopefully wake up a coro so the scheduler can run it. -Note that the callback I, under any circumstances, block -the current coro. Normally, this is achieved by having an "idle -coro" that calls the event loop and then blocks again, and then -readying that coro in the idle handler, or by simply placing the idle -coro in this variable. - -See L or L for examples of using this -technique. - -Please note that if your callback recursively invokes perl (e.g. for event -handlers), then it must be prepared to be called recursively itself. +See L or L for examples of using this technique. =cut -$idle = sub { - require Carp; - Carp::croak ("FATAL: deadlock detected"); +# ||= because other modules could have provided their own by now +$idle ||= new Coro sub { + require Coro::Debug; + die "FATAL: deadlock detected.\n" + . Coro::Debug::ps_listing (); }; # this coro is necessary because a coro @@ -209,14 +197,6 @@ print "@_\n"; } 1,2,3,4; -=cut - -sub async(&@) { - my $coro = new Coro @_; - $coro->ready; - $coro -} - =item async_pool { ... } [@args...] Similar to C, but uses a coro pool, so you should not call @@ -282,7 +262,7 @@ Calls the scheduler. The scheduler will find the next coro that is to be run from the ready queue and switches to it. The next coro to be run is simply the one with the highest priority that is longest -in its ready queue. If there is no coro ready, it will clal the +in its ready queue. If there is no coro ready, it will call the C<$Coro::idle> hook. Please note that the current coro will I be put into the ready @@ -635,7 +615,18 @@ coro. This method simply sets the C<< $coro->{desc} >> member to the given -string. You can modify this member directly if you wish. +string. You can modify this member directly if you wish, and in fact, this +is often preferred to indicate major processing states that cna then be +seen for example in a L session: + + sub my_long_function { + local $Coro::current->{desc} = "now in my_long_function"; + ... + $Coro::current->{desc} = "my_long_function: phase 1"; + ... + $Coro::current->{desc} = "my_long_function: phase 2"; + ... + } =cut @@ -688,6 +679,10 @@ otherwise you might suffer from crashes or worse. The only event library currently known that is safe to use without C is L. +Coro will try to catch you when you block in the event loop +("FATAL:$Coro::IDLE blocked itself"), but this is just best effort and +only works when you do not run your own event loop. + This function allows your callbacks to block by executing them in another coro where it is safe to block. One example where blocking is handy is when you use the L functions to save results to @@ -738,7 +733,7 @@ } } -=item $cb = Coro::rouse_cb +=item $cb = rouse_cb Create and return a "rouse callback". That's a code reference that, when called, will remember a copy of its arguments and notify the owner @@ -746,7 +741,7 @@ See the next function. -=item @args = Coro::rouse_wait [$cb] +=item @args = rouse_wait [$cb] Wait for the specified rouse callback (or the last one that was created in this coro). @@ -853,8 +848,9 @@ =item coro switching is not signal safe -You must not switch to another coro from within a signal handler -(only relevant with %SIG - most event libraries provide safe signals). +You must not switch to another coro from within a signal handler (only +relevant with %SIG - most event libraries provide safe signals), I +you are sure you are not interrupting a Coro function. That means you I call any function that might "block" the current coro - C, C C<< Coro::Semaphore->down >> or @@ -864,6 +860,67 @@ =back +=head1 WINDOWS PROCESS EMULATION + +A great many people seem to be confused about ithreads (for example, Chip +Salzenberg called me unintelligent, incapable, stupid and gullible, +while in the same mail making rather confused statements about perl +ithreads (for example, that memory or files would be shared), showing his +lack of understanding of this area - if it is hard to understand for Chip, +it is probably not obvious to everybody). + +What follows is an ultra-condensed version of my talk about threads in +scripting languages given on the perl workshop 2009: + +The so-called "ithreads" were originally implemented for two reasons: +first, to (badly) emulate unix processes on native win32 perls, and +secondly, to replace the older, real thread model ("5.005-threads"). + +It does that by using threads instead of OS processes. The difference +between processes and threads is that threads share memory (and other +state, such as files) between threads within a single process, while +processes do not share anything (at least not semantically). That +means that modifications done by one thread are seen by others, while +modifications by one process are not seen by other processes. + +The "ithreads" work exactly like that: when creating a new ithreads +process, all state is copied (memory is copied physically, files and code +is copied logically). Afterwards, it isolates all modifications. On UNIX, +the same behaviour can be achieved by using operating system processes, +except that UNIX typically uses hardware built into the system to do this +efficiently, while the windows process emulation emulates this hardware in +software (rather efficiently, but of course it is still much slower than +dedicated hardware). + +As mentioned before, loading code, modifying code, modifying data +structures and so on is only visible in the ithreads process doing the +modification, not in other ithread processes within the same OS process. + +This is why "ithreads" do not implement threads for perl at all, only +processes. What makes it so bad is that on non-windows platforms, you can +actually take advantage of custom hardware for this purpose (as evidenced +by the forks module, which gives you the (i-) threads API, just much +faster). + +Sharing data is in the i-threads model is done by transfering data +structures between threads using copying semantics, which is very slow - +shared data simply does not exist. Benchmarks using i-threads which are +communication-intensive show extremely bad behaviour with i-threads (in +fact, so bad that Coro, which cannot take direct advantage of multiple +CPUs, is often orders of magnitude faster because it shares data using +real threads, refer to my talk for details). + +As summary, i-threads *use* threads to implement processes, while +the compatible forks module *uses* processes to emulate, uhm, +processes. I-threads slow down every perl program when enabled, and +outside of windows, serve no (or little) practical purpose, but +disadvantages every single-threaded Perl program. + +This is the reason that I try to avoid the name "ithreads", as it is +misleading as it implies that it implements some kind of thread model for +perl, and prefer the name "windows process emulation", which describes the +actual use and behaviour of it much better. + =head1 SEE ALSO Event-Loop integration: L, L, L.