@hiredman It appears the promise-chan issue we discussed last week is somewhat worse than I thought. It looks like a fulfilled promise-chan will always be preferred by alts! to a timeout chan, even if the timeout chan has already been triggered (ie, x millis have passed).
alts! randomizes the order in which it evaluates channels unless you set :priority @pmooser
If you alts! over ready channels (like a fulfilled promise or an elapsed timeout) you should get an even distribution of chosen ops
If that isn’t the case, I’d like to see a minimal repro case
@ghadi if you have an alts! in a loop, even if the timeout expires, the js thread isn't yielded, so the fact that the timeout has expired is never registered
because alts!, if it can proceed right way, never yields control of the js thread
@ghadi As requested, here is your case:
javascript, right? @pmooser
Yes, cljs
I actually have not run that snippet in clj, so I'm not sure if it would be the same.
Actually I suspect it won't be, based on some tests I had before, but I'm not 100%.
it makes sense given the background from @hiredman
99% sure it is different in clj
I don't agree. I mean I "understand why" from the implementation, but it doesn't make sense in "this is non-surprising and what everyone would expect from a supposedly non-deterministic choice".
It's basically an implementation detail, and it is undesirable.
yeah I also don't think it is correct -- I meant it makes sense given the impl in cljs
In my opinion, we shouldn't have to know the type of chans to know if our code will behave as expected - especially since chans have no mechanism for tracking identity, like a name or even an IMeta implementation.
Anyway, I am guessing this will never be addressed but it is definitely unfortunate. I just provided my own implementation of promise-chan that doesn't do this (because it is not based on an infinite buffer) and we will probably always avoid the other one just to be sure not to run into this.
I think it's basically an edge case of an implementation detail that rears its head because most buffers won't infinitely provide values (and thus be preferred indefinitely).
it's not a problem with promise-chan
it's a problem that the timeout is never fulfilled
That is not true.
The code fulfills the timeout before alts-ing.
Note the:
(<! t)
oh -- I misread
what mod did you make to promise-chan?
(in clj it behaves)
I wrote my own, and didn't implement it as a buffer. I implement ReadPort and WritePort myself, with a go-loop handling reads and writes (and deferring to some internal chans).
Thank you for testing it in clj!
Basically the trick (I think) is that I'm providing the same API, but because I'm falling back to operations on normal many-to-many chans and using a go-loop to ferry values around, it does yield as expected.
I'm sure it is marginally less efficient,
but for my use, the efficiency of this won't pose a problem,
especially given the alternatives.
One moment, I want to write another test to confirm a suspicion ...
Ok, yes, it works how I thought.
So it looks like any buffered chans with ready values will always be preferred over the timeout chan, even if the timeout has already triggered.
yup ^ it's not a promise-chan problem
Sure, but the reason a promise chan is "the problem" for me is that no other chan (that I know of) will indefinitely provide values. Ie, a normal buffered chan will exhaust its buffer pretty soon, and then at least timeouts/etc will get a chance.
So while it isn't specific to promise chan technically, the fact that it can basically get "stuck" doesn't really occur with any other buffer implementation I've seen.
cljs.user=> (dotimes [i 10] (println (clojure.core.async/random-array 2)))
WARNING: var: cljs.core.async/random-array is not public at line 1 <cljs repl>
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
#js [1 0]
@pmooser @hiredman I had a feeling we didn't have all the facts straight. alts!
is broken in the 2 channel but not in the three+ channel casecljs.user=> (dotimes [i 10] (println (clojure.core.async/random-array 3)))
WARNING: var: cljs.core.async/random-array is not public at line 1 <cljs repl>
#js [1 2 0]
#js [2 0 1]
#js [2 0 1]
#js [1 2 0]
#js [1 2 0]
#js [1 2 0]
#js [2 0 1]
#js [1 2 0]
#js [2 0 1]
#js [2 0 1]
thanks for the report @pmooser, we'll get that fixed
@ghadi Really? That would be great!! Thank you.
so it has nothing to do with the channels 🙂
it's alts!
always trying in the same order
Yeah, in my case, it wasn't just two chans, but the other chan had no values
even the 3+ channel case it looks like channel 1 is never tried first
But I am glad to hear that it is something understandable and that you think it might even get fixed!!