In most “select” implementations a set of “ready” endpoints is returned. So it is trivial for the reader to prioritize some endpoints over others.
Because of the way Go select works it is more difficult - requiring nested selects - and it is more easily implemented using multiple readers and queues once it moves beyond a few producers. > On May 3, 2021, at 1:23 PM, 'Axel Wagner' via golang-nuts > <golang-nuts@googlegroups.com> wrote: > > > On Mon, May 3, 2021 at 6:34 PM Øyvind Teig <oyvind.t...@teigfam.net> wrote: >>>> meaning that there is not any state where random select is ever used. >>> It is. >> Trouble A: If random select is never used […] > > I was unclear: When I said "It is", I meant "it is used". Your understanding > of what select does is correct. There will be cases, where both channels are > ready when the inner `select` is entered and thus, there will be a > pseudorandom choice over which will proceed. > > The argument put forward is that that's exactly how a priority select would > have to behave as well. As least as I imagine it and as well as I understand > the implementation of `select` (which is, admittedly, not *super* well). > >> If so, maybe a constructive point is to try to write some runnable Go code >> that uses this pri select pattern. I have thought about it, but I don't know >> how to check whether it would ever enter one of the selects > > This is precisely what my question was getting at. FWIW, it's ultimately > pretty straight forward to demonstrate this behavior: > https://play.golang.org/p/UUA7nRFdyJE > This program exits if and only if the inner select choses `lo`. Given that we > know that `hi` is being closed before `lo` ("Within a single goroutine, the > happens-before order is the order expressed by the program."), `lo` being > ready implies `hi` being ready as well. Thus, by seeing that the program > exits, we can show that the inner select sometimes chooses the `lo` case, > even though the `hi` is ready as well. > > Crucially, however, we needed to know that `close(hi)` happens before > `close(lo)` to prove this case was taken - thus, the communications are not > concurrent. That's what I meant by "external synchronization primitives". > > I think my question was flawed, because really, the issue isn't about how the > `select` with `default` construct we showed works - the question is how a > priority `select` could work. That is, could we implement a priority `select` > such that this code terminates: https://play.golang.org/p/4G8CY36L0Qy > > I don't think we can - and based on that assumption I extrapolated how a > priority select would actually behave - but I have to admit that I really > don't understand `select` or the underlying hardware primitives enough to > make a solid case either way here. Maybe you can provide an equivalent > program in a language of your choice that terminates - that would certainly > prove that it's at least possible (though to be clear: I don't understand > your xC code, so I can't promise that I'd understand whatever you send here, > personally :) ). > > All of that being said: I really think that in the cases where a priority > select is needed, this construct is good enough to hold up. > >> and in fact need to do a random select, and select a lower when a higher is >> present (or became present). Plus, if I try to synchronise clients and send >> over sequence counts, the scheduling pattern could become so repetitive that >> no such situation would occur. >> >> Is there a way to inspect the built code and do it from code inspection? (I >> guess so?) >> >> But for all this, I would need even more help... >> >> (Maybe I'll try to trigger a student since I have so much xC ahead of me..) >> >> Øyvind >> >>>> rog wrote above (where I had indicated that occam (and also xC, said here) >>>> has a looping channel construct): "To start with, if you've got N clients >>>> where N isn't known in advance, it's not possible to use Go's select >>>> statement directly because it doesn't provide support for reading from a >>>> slice." Does this mean that aside from reflection >>>> (https://go2goplay.golang.org/p/S_5WFkpqMP_H - which still does not serve >>>> "client 2", shouldn't it?) then idiomatic Go for a small number of >>>> priorities is the one with default case(s), and it works 100% as intended, >>>> with no cognitive (?) reliance on Go's inner working under the hood? (I >>>> mean: "WYSIWYG semantics" kind of.) >>>> >>>> I am at a point now that if the answer to the above is yes, I'll just say >>>> thank you for your help, and I will be a Go-wise wiser person. With my >>>> cognitive bias I will then have to accept that this is Go, nothing more to >>>> say. Just accept it. Anyhow, in case, thank you! >>>> >>>> Øyvind >>>> >>>> fredag 30. april 2021 kl. 10:42:47 UTC+2 skrev axel.wa...@googlemail.com: >>>>>> On Fri, Apr 30, 2021 at 9:53 AM Øyvind Teig <oyvin...@teigfam.net> wrote: >>>>>> If there is no notion of simultaneity why all the effort to describe the >>>>>> random distribution? >>>>> >>>>> While it's not possible for two cases to become ready at the same time, >>>>> it's definitely possible for two cases to be ready when entering a >>>>> select. That's where the random selection comes in. >>>>> >>>>> There's also the notable difference between a select with a default and >>>>> one without. A select with a default never blocks, so which branch is >>>>> taken is *only* determined by what's ready when entering the select, >>>>> whereas a select without can block and then gets woken up by the first >>>>> communication that's ready - and there'll always be a "first". >>>>> >>>>> In a sense, the nested select uses that: The outer select handles the >>>>> "what's currently ready" case and the inner select handles the "what >>>>> becomes ready in the future". >>>>> >>>>> The priority select would use the same basic logic: >>>>> - Is the high priority case ready? If so, do that >>>>> - If not, block until one of the cases become ready - do the first that >>>>> becomes ready >>>>> >>>>> The crux here is exactly that we can't have two cases "becoming ready" at >>>>> the same time, so we really *have* to "take the first one that becomes >>>>> ready". >>>>> >>>>>> The select is first set up, at which time the code decides on which one >>>>>> to take if more than one guard is ready. If the clients were only >>>>>> sending, then nowhere in the system is this noted on "the other" side of >>>>>> the channel (in the server) before it enters the select. The channel >>>>>> would have noted the first contender, yes, but the servre have yet no >>>>>> idea. If none is ready, then the server was first on all the ends, and >>>>>> when a sender arrives it will match the guard set in the server and tear >>>>>> down the select. In due time the server is scheduled with that one event. >>>>>> >>>>>> This is how I have seen it in several systems. I wonder what might be so >>>>>> different with go. >>>>> >>>>> I don't think I understand this exposition. But on first glance, your >>>>> description doesn't sound terribly different from what's happening in Go. >>>>> >>>>> To be clear: No one is claiming it would be impossible to implement a >>>>> priority select in Go. Obviously we could replace the pseudo-random >>>>> choice by something else. We are just saying that it would be equivalent >>>>> to the nested select code. >>>>> >>>>>> Ok, so this is a pattern that Go people would use if they needed to do >>>>>> pri select. Then, why go to the lengths of the other code shown above? >>>>>> Is it because I have kind of "pressed" you to come up with code and then >>>>>> of course, one thing may be solved several ways? >>>>> >>>>> I think the first code you where shown by Jan (which is the same as >>>>> Ian's) is correct and I believe it's likely that your insistence that it >>>>> isn't is what prompted people to come up with more and more complicated >>>>> code. >>>>> >>>>>> Will your Go code examples stand the test of formal verification? Of >>>>>> course, when it's not formally verified you probaby could not answer >>>>>> such a question. But the stomach feeling? >>>>> >>>>> I'm not very familiar with formal methods for this, or what the invariant >>>>> is that would be verified. >>>>> I do feel quite confident about the statement that the shown snippet is >>>>> equivalent to how I'd think a priority select would work. >>>>> >>>>>> Another angle: Go does not have the expression before the select that >>>>>> evaluates to true or false. Nothing like >>>>>> >>>>>> select { >>>>>> case (do_this) => val1 <-c1: >>>>>> case val2 <-c2: >>>>>> } >>>>>> >>>>>> Instead, the chan is set to nil to exclude it from the set. What might >>>>>> happen if we had a set of 100 clients and they were switched on and off >>>>>> internally in the server (that's their purpose) - when will the uniform >>>>>> distribution be reset? What's the life span of the distribution? With a >>>>>> psudorandom sequence any one value is only visited once on a round. >>>>> >>>>> I'm not sure what you mean here. Is what you call a "round" the cycle of >>>>> the PRNG? In that case, this statement isn't true, the cycle is likely >>>>> significantly longer than the number of cases. So we definitely chose at >>>>> least one case multiple times per cycle. >>>>> >>>>> AFAIK this is the PRNG used by the select, FWIW. I assume it simply calls >>>>> into it (or likely `fastrandn` directly below) when entering a select >>>>> with multiple available cases. >>>>> >>>>>> We still want this to be fair. Could those having been served be served >>>>>> again (before the others) after a reset of the distribution, and this >>>>>> introduce a notion of unfairness? >>>>> >>>>> It can definitely happen, but I'm not sure that "unfairness" is a >>>>> meaningful term here. AIUI the process is "if the runtime enters a select >>>>> and multiple cases are ready, it chooses one uniformly at random" (within >>>>> the limits of the PRNG). Yes, as an outcome this can mean that one case >>>>> is hit more often than the others. But all cases are equally likely to be >>>>> hit more often. And by the law of large numbers, you'd expect the >>>>> distribution to flatten over time. >>>>> >>>>>> (I gues that jamming is that only one client alone gets to the server, >>>>>> whereas starving is that a client never gets to the server). >>>>> >>>>> Both are statistically unlikely, if we assume the PRNG is reasonably good >>>>> - which I think we can, it has been subjected to reasonable statistical >>>>> tests. >>>>> >>>>>> >>>>>> Øyvind >>>>>> >>>>>>> >>>>>>> Ian >>>>> >>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "golang-nuts" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>> an email to golang-nuts...@googlegroups.com. >>>>> >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/golang-nuts/ec5e5c0f-c5bf-4efb-b1c4-dc056720ba5cn%40googlegroups.com. >>>> >>>> -- >>>> You received this message because you are subscribed to the Google Groups >>>> "golang-nuts" group. >>>> To unsubscribe from this group and stop receiving emails from it, send an >>>> email to golang-nuts...@googlegroups.com. >>> >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/golang-nuts/9186c34b-1088-4ae0-8076-6c5cd0cdde38n%40googlegroups.com. >>>> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/cda2055a-8024-4ab1-87ca-18a177aa1cb2n%40googlegroups.com. > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CAEkBMfFOUfDQJSpFQCOUAs%2BtKEATNO8K3pj0ZA%3DvRmNXDMokDg%40mail.gmail.com. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/637AEE22-8F66-4933-A6FA-C84CB050C1E9%40ix.netcom.com.