Skip to content

Commit 6e8b79e

Browse files
committed
Move introduction of outcome {} after Channel
The way it was, we're starting to discuss Channels in the context of outcome before we specced what a Channel is.
1 parent 4134f88 commit 6e8b79e

File tree

1 file changed

+55
-54
lines changed

1 file changed

+55
-54
lines changed

S17-concurrency.pod

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,61 @@ result.
377377
This simply calls C<result> on each of the C<Promise>s, so any exception will
378378
be thrown.
379379

380-
There is also an C<outcome> statement [keywords still negotiable]. In its
380+
=head1 Channels
381+
382+
A C<Channel> is essentially a concurrent queue. One or more threads can put
383+
values into the C<Channel> using C<send>:
384+
385+
my $c = Channel.new;
386+
$c.send($msg);
387+
388+
Meanwhile, others can C<receive> them:
389+
390+
my $msg = $c.receive;
391+
392+
Channels are ideal for producer/consumer scenarios, and since there can be
393+
many senders and many receivers, they adapt well to scaling certain pipeline
394+
stages out over multiple workers also. [Conjectural: The two feed operators
395+
C<< ==> >> and C<< <== >> are implemented using Channel to connect each of
396+
the stages.]
397+
398+
A C<Channel> may be "forever", but it is possible to close it to further
399+
sends by telling it to C<close>:
400+
401+
$c.close();
402+
403+
Trying to C<send> any further messages on a closed channel will throw the
404+
C<X::Channel::SendOnDone> exception. Closing a channel has no effect on the
405+
receiving end until all sent values have been received. At that point, any
406+
further calls to receive will throw C<X::Channel::ReceiveOnDone>. The
407+
C<done> method returns a C<Promise> that is kept when a sender has
408+
called C<close> and all sent messages have been received. Note that multiple
409+
calls to a channel return the same promise, not a new one.
410+
411+
While C<receive> blocks until it can read, C<poll> takes a message from the
412+
channel if one is there or immediately returns C<Nil> if nothing is there.
413+
414+
The C<outcome> construct also works on channels, and will try to receive
415+
values from the any C<Channel> that has value(s) available until they are
416+
all closed.
417+
418+
outcome {
419+
whenever $channel { take $_ }
420+
}
421+
422+
This is such a common pattern that we make a channel in list context behave
423+
that way:
424+
425+
for @$channel -> $val { ... }
426+
for $channel.list -> $val { ... }
427+
428+
(Note that this is not a combinator, but a means for transfering data from
429+
the reactive realm to the lazy realm. Some reasonable amount of buffering
430+
is assumed between the two.)
431+
432+
=head1 Outcome
433+
434+
There is an C<outcome> statement [keywords still negotiable]. In its
381435
simplest form it just takes a list of C<Promise>s and C<Channel>s and returns
382436
a lazy list of all the values returned by all Promises and Channels specified:
383437

@@ -427,7 +481,6 @@ timing out.
427481
wait 5 { say "Not done yet" }
428482
}
429483

430-
431484
As a degenerate case, in order to avoid blocking at all you may use a
432485
C<wait 0>. Together with C<last>, this allows one to exit the C<outcome>
433486
prematurely whenever there is nothing happening:
@@ -458,58 +511,6 @@ like this:
458511
# do other stuff
459512
}
460513

461-
=head1 Channels
462-
463-
A C<Channel> is essentially a concurrent queue. One or more threads can put
464-
values into the C<Channel> using C<send>:
465-
466-
my $c = Channel.new;
467-
$c.send($msg);
468-
469-
Meanwhile, others can C<receive> them:
470-
471-
my $msg = $c.receive;
472-
473-
Channels are ideal for producer/consumer scenarios, and since there can be
474-
many senders and many receivers, they adapt well to scaling certain pipeline
475-
stages out over multiple workers also. [Conjectural: The two feed operators
476-
C<< ==> >> and C<< <== >> are implemented using Channel to connect each of
477-
the stages.]
478-
479-
A C<Channel> may be "forever", but it is possible to close it to further
480-
sends by telling it to C<close>:
481-
482-
$c.close();
483-
484-
Trying to C<send> any further messages on a closed channel will throw the
485-
C<X::Channel::SendOnDone> exception. Closing a channel has no effect on the
486-
receiving end until all sent values have been received. At that point, any
487-
further calls to receive will throw C<X::Channel::ReceiveOnDone>. The
488-
C<done> method returns a C<Promise> that is kept when a sender has
489-
called C<close> and all sent messages have been received. Note that multiple
490-
calls to a channel return the same promise, not a new one.
491-
492-
While C<receive> blocks until it can read, C<poll> takes a message from the
493-
channel if one is there or immediately returns C<Nil> if nothing is there.
494-
495-
The C<outcome> construct also works on channels, and will try to receive
496-
values from the any C<Channel> that has value(s) available until they are
497-
all closed.
498-
499-
outcome {
500-
whenever $channel { take $_ }
501-
}
502-
503-
This is such a common pattern that we make a channel in list context behave
504-
that way:
505-
506-
for @$channel -> $val { ... }
507-
for $channel.list -> $val { ... }
508-
509-
(Note that this is not a combinator, but a means for transfering data from
510-
the reactive realm to the lazy realm. Some reasonable amount of buffering
511-
is assumed between the two.)
512-
513514
=head1 Supplies
514515

515516
Channels are good for producer/consumer scenarios, but because each worker

0 commit comments

Comments
 (0)