There's a reason Go doesn't support non-random selects. Often, you'll be selecting on channels which peers are accessing concurrently. In this situation, there's no ordering guarantee between when different cases will become available. If case 2 can become available ever-so-slightly before case 1, or ever-so-slightly after, then which case will be selected ends up random. However, if the scheduler happens to schedule the peer for case 1 and doesn't schedule the peer for case 2 until the peer for case 1 blocks, then this could give a false appearance of determinism, and someone could write code depending on a race condition by accident. Also, you could end up with a situation where the peer for case 2 is under-serviced because the peer for case 1 is always waiting when the select statement is executed.
Your situation is odd because there *is* an ordering guarantee between when the select cases become available, because there's only one sender. In that case, you'd really only need one channel except that you're sending two different types of requests, whose meaning is partially determined by what channel they're sent on. You could instead use a single channel and avoid select entirely with struct Request { Work: *WorkItem; Idle: bool } You could then send Request{ Work: NewWorkItem() } or Request{ Idle: true } (or maybe Request{ Idle: responseChannel }) over a single channel and not have to worry about trying to bend select into a different shape. On Fri, May 11, 2018 at 12:36 PM T L <tapir....@gmail.com> wrote: > > > On Friday, May 11, 2018 at 11:54:16 AM UTC-4, Jake Montgomery wrote: >> >> As others on this thread have pointed out, this use case does not >> actually require select where the cases are checked in order. >> >> However, for completeness, if you need to check two channels, and they >> must be checked in order, then use two select statements with defaults: >> for { >> select { >> case wi := <-work_ch: >> self.do_the_work(wi) >> default: >> } >> select { >> case <-self.idle_request: >> self.idle_response <- true >> default: >> } >> } >> >> Again, this should rarely be necessary, or even useful. But there it is. >> > > > Good point, but it is too cpu consuming. > I think the following one is better. > > for { > > select { > case <-self.idle_request: > self.idle_response <- true > default: > } > > > select { > > case wi := <-work_ch: > self.do_the_work(wi) > case <-self.idle_request: > self.idle_response <- true > } > } > > But I think if it would be even better if Go support non-random select > blocks. > > > >> >> >> On Friday, May 4, 2018 at 10:24:56 AM UTC-4, Andriy Pylypenko wrote: >>> >>> Hi, >>> >>> I have a scenario which I haven't found a way to implement with the Go >>> channels and select statement while it's no problem to do it with the >>> select()/poll() functions. The scenario is as follows. >>> >>> Let me use a Go-like pseudo-code to demonstrate the idea. There is a >>> source of a work items which are processed by several goroutines. Here is >>> the source procedure: >>> >>> work_ch := make(chan *WorkItem) >>> >>> for { >>> work_ch <- NewWorkItem() >>> } >>> >>> And here is the worker thread: >>> >>> for { >>> wi := <-work_ch >>> self.do_the_work(wi) >>> } >>> >>> Now I need to suspend the work. I stop supplying the work items and want >>> to make sure the worker goroutines are done with the work. The source >>> procedure becomes something like this: >>> >>> for { >>> if suspend_requested { >>> for _, worker := range workers { >>> worker.idle_request <- true >>> } >>> for _, worker := range workers { >>> <-worker.idle_response >>> } >>> report_suspend_is_success() >>> wait_until_unsuspended() >>> } >>> work_ch <- NewWorkItem() >>> } >>> >>> And I want to modify the worker thread like this: >>> >>> for { >>> select { >>> case wi := <- work_ch: >>> self.do_the_work(wi) >>> case <-self.idle_request: >>> self.idle_response <- true >>> } >>> } >>> >>> However this last snippet of code does not work because the cases within >>> the select statement are randomly chosen when both channels are ready so I >>> have no guarantee that the first case is executed first. >>> >>> Talking about the select() or poll() functions from the C library which >>> evidently were an inspiration for the Go select statement, there is no >>> problem with the described approach. It's because the select() function >>> returns a complete information about the state of all the monitored >>> descriptors and allows the programmer to decide what he wants to read or >>> write and in which order, based on readiness of every descriptor. >>> >>> I think it would be a great idea to have some function similar to >>> select()/poll() but working with the Go channels. >>> >> -- > 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. > For more options, visit https://groups.google.com/d/optout. > -- 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. For more options, visit https://groups.google.com/d/optout.