Right. Then I guess it's not a regression. Tag removed. On 2017-10-16 07:42:06, jn...@jnthn.net wrote: > On Fri, 13 Oct 2017 20:43:42 -0700, alex.jakime...@gmail.com wrote: > > Code: > > my $s1 = Supplier.new; $s1.Supply.tap: { say $_; $s1.emit(2) if $++ < > > 5; say "here" }; $s1.emit(1) > > > > > > ¦2017.06: > > 1 > > 2 > > 2 > > 2 > > 2 > > 2 > > here > > here > > here > > here > > here > > here > > > > ¦HEAD(012c80f): > > 1 > > here > > 2 > > > > > > Possible IRC discussion: https://irclog.perlgeek.de/perl6-dev/2017- > > 09- > > 21#i_15197905 > > > > The behavior change two times, first it started hanging after > > (2017-09-18) > > https://github.com/rakudo/rakudo/commit/4a8038c2956e863bc661a2a00e8371eb98002608 > > And then the hang was resolved (incorrectly?) in > > (2017-09-22) > > https://github.com/rakudo/rakudo/commit/547839200a772e26ea164e9d1fd8c9cd4a5c2d9f > > > > > > I think the output on 2017.06 makes more sense. > > Actually the 2017.06 behavior was clearly wrong, because it violates > the principle that a Supply chain will process a message at a time. > That every "here" comes out at the end illustrates that the tap block > was reentered. That was not an intended behavior, but rather an > accident resulting through use of a reentrant mutex for some (not all) > Supply concurrency management. > > The commits in question and those around them introduced a unified > concurrency model for all Supply operations, including `supply` > blocks, based around Lock::Async. The changes fixed many other issues, > but also forced a revisit of the question of recursion - effectively, > a supply sending a message to itself. This is a tricky problem, > because there's some competing design goals around supplies: > > 1. Serial message processing (as mentioned above) > 2. Back-pressure: those who emit into a Supply chain pay the cost of > the message processing. > 3. Fairness: Messages are processed in the order they arrive. > 4. No concurrency unless requested > > I think 1 is pretty non-negotiable, because it's hard to write > reliable concurrent code if you don't know what your "transaction > scope" is. I really should have noticed the issue with reentrant > mutexes sooner, though I guess that's my own usage biases to blame: I > very rarely use `.tap` and instead use supply/react/whenever where > this issue could never happen (but - big issue - the old supply block > mechanism violated goal 2 and arguably 3). > > So the interesting question is how many we can have out of 2, 3, and > 4. The current solution, on recursion, is to schedule the recursive > message handling using the current $*SCHEDULER. This makes sure that > we get 1 and 3. Unfortunately, it violates 2 (if we expect it to be > transitively applied) and 4, and it's 4 that results in the effects > reported here. > > Note that if it's rewritten as: > > my $s1 = Supplier.new; react { whenever $s1 { say $_; $++ < 5 ?? > $s1.emit(2) !! $s1.done; say "here" }; $s1.emit(1) } > > Then it works fine: > > 1 > here > 2 > here > 2 > here > 2 > here > 2 > here > 2 > here > > Also if you sleep a bit after the original: > > my $s1 = Supplier.new; $s1.Supply.tap: { say $_; $s1.emit(2) if $++ < > 5; say "here" }; $s1.emit(1); sleep 1 > > Then the output is the same as the above also (of course, the react > block way is the correct one, not sleeping!) > > So the question is if we can find a way to have 2 and 4, while > retaining 1 and 3, and at what cost.
[perl #132292] Recursively .emit-ing from the tap of the same supply bails out
Aleks-Daniel Jakimenko-Aleksejev via RT Mon, 16 Oct 2017 11:38:31 -0700