Can somebody explain the importance of 'select'?

瀏覽次數:377 次
跳到第一則未讀訊息

John C.

未讀,
2017年1月19日 中午12:33:382017/1/19
收件者:golang-nuts
On several occasions the Go designers have alluded to the fact that the 'select' mechanism and the fact that it's built in to the language are very important for concurrency (can't seem to find references).  While I understand just fine how to use select/goroutines/channels, the overarching importance of select as a built-in feature is escaping me.

Can somebody help me see the big "why" picture better?

Thanks,
John C.

Chris Hines

未讀,
2017年1月19日 下午1:57:282017/1/19
收件者:golang-nuts
I believe the primary reason why select must be in the language is because it integrates tightly with goroutine scheduling to efficiently block, and then wake up when one of its channel operations can complete.

Thomas Solignac

未讀,
2017年1月19日 下午2:03:552017/1/19
收件者:golang-nuts
Let's say you make a sudoku solver, as fast as possible.
You have a multicore computer.

If the disk read or parsing is slow, you are going to prepare sudoku files in 3 goroutines, let's say.
And the 4th thread (the main thread, let's say) will solve them.

How the main thread can get sudoku to solve from the goroutines ?

Of course, the channel let you send each sudoku from the reader goroutines to the main thread. But :

2 bad possibilities :

1- You read a goroutine. But it's blocking and maybe another is ready faster. You can't check.
2- You read all of them in a no-blocking way, constantly checking all of them. It's a hell-loop, consuming a lot of CPU.

Here is the power of select.

You just do this :

for {
select {
case sudoku <- chanReaderA:
solve(sudoku)
case sudoku <- chanReaderB:
solve(sudoku)
     case sudoku <- chanReaderC:
solve(sudoku)
}
}
}

What happens ?

The select "pauses" your program, listening to all those 3 channels. It waits for a message.
When a message come, it launch the corresponding instruction. Here, always the same instruction : "solve(sudoku)"

It's not only about performance : It's readable and short.

Ian Lance Taylor

未讀,
2017年1月20日 凌晨12:17:482017/1/20
收件者:John C.、golang-nuts
Are you asking "why is select needed at all?" or are you asking "why
does select have to be built into the language?"

Ian

Jesper Louis Andersen

未讀,
2017年1月20日 凌晨3:52:142017/1/20
收件者:Ian Lance Taylor、John C.、golang-nuts
One subtlety of having a built in concurrency model is that you avoid stripey programs[0]

If there is only one concurrency model, programs are built to match that concurrency model. If the model is in a library, you often have several competing concurrency models. This means that programs and libraries have "color" in the sense that some libraries only work with some specific other libraries. In practice, this divides a community into camps/clans/tribes where you can't readily share code between the camps. It leads to rewrites of perfectly fine code in order to make it fit into another model of concurrency.

Contrast with a system such as Go: by picking a concurrency model up front, you can be reasonably sure the library you are looking at will work without too many assumptions about the underlying structure.

Where such observations break apart is as soon as you look at Go's `context` package, or at Erlang's `OTP principles`. There, the underlying model is extended with certain rules. These rules make code able to coexist nicely in a system at the expense of giving the code color.

If you look at the design of good concurrency models, they make it easy to move code around in a project without having to worry about which process/goroutine/context that code ran in. This is the reason why you have no goroutine identity.

You could have made most of Go's concurrency into a library, but the model would be slightly more complicated. For 'select' to be a library, you need to have each case in the select be a first-class value you can pass around in the program and then you need a function which can combine these values into a single select case. A slightly weaker model is to have a select-this-event-ORELSE-select-that-event operator (see e.g., Haskell's STM and its `orElse` operator).

However, by making it into a library, you possibly made the program less efficient than a built-in solution. With enough compiler machinery, you may be able to get back most of this efficiency, but it is not a priori clear it outweighs the cost.


[0] This is a total aside: ever wondered why female cats have splotches of color males do not? Well, the color sits on the X chromosome of which the female cat has two. Early in the embryo, a deactivation process of one of the X's happens with about a 50/50 split. Cell growth then produces said cat, but depending on where the cell came from, fur has different colors. The same thing happens in human females, though there is no visible change due to this. And yes, it is completely irrelevant information, but I like to see programs as being stripey in this way, depending on what chromosomes it has.


--
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.
For more options, visit https://groups.google.com/d/optout.

John C.

未讀,
2017年1月20日 中午12:59:332017/1/20
收件者:golang-nuts、ia...@golang.org、jscroc...@gmail.com
Thank you for the explanations.  I also received a helpful note off list, put here for posterity:


--------------------------

Correct! ;-)
---

Aha, I have no way of finding out whether a channel is ready to proceed without actually proceeding or blocking.

On xxxxx wrote:
On xxxxx wrote:


> While I understand just fine how to use select/goroutines/channels, the overarching importance of select as a built-in feature is escaping me.

I suggest a thought experiment. You understand just fine how to use the select statement, so maybe try to imagine how are you'd code some task, where you use normally use select, _without_ it. What'll be the [most important] difference?
-- 

-j

Konstantin Khomoutov

未讀,
2017年1月21日 清晨5:30:312017/1/21
收件者:John C.、golang-nuts、ia...@golang.org
On Fri, 20 Jan 2017 09:59:33 -0800 (PST)
"John C." <jscroc...@gmail.com> wrote:

> Thank you for the explanations. I also received a helpful note off
> list, put here for posterity:

>>> I suggest a thought experiment. You understand just fine how to
>>> use the select statement, so maybe try to imagine how are you'd
>>> code some task, where you use normally use select, _without_ it.
>>> What'll be the [most important] difference?
>> Aha, I have no way of finding out whether a channel is ready to
>> proceed

Note that another important property of the select statement is that it
allows you to uniformly wait on several different channels at the same
time.

Again, as pointed out by other persons (and especially well put by J.L.
Andersen -- as usually), everything the select statement can do could
also been done using a library, but the resulting code looks ugly.
If you had experience implementing, say, asynchronous I/O with timeouts
using something like C or C++ or Delphi and the OS's native API for
this, you would not actually ask your question: you'd know that
(almost¹) everything Go built-in concurrency offers can be done
using a more low-level language and the APIs provided by the underlying
OS but this is a) way more work; b) the result looks way more ugly.

¹ http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/

Val

未讀,
2017年1月21日 清晨6:15:072017/1/21
收件者:golang-nuts、ia...@golang.org、jscroc...@gmail.com
Hello John
Not sure how relevant for the topic, but:  there exist a way to "try to read a channel, in a non-blocking way if no value is ready yet", using default :

    select {
    case x, ok := <-ch:
        if ok {
            fmt.Printf("Value %d was read.\n", x)
        } else {
            fmt.Println("Channel closed!")
        }
    default:
        fmt.Println("No value ready, moving on.")
    }

see http://stackoverflow.com/questions/3398490/checking-if-a-channel-has-a-ready-to-read-value-using-go/14092860#14092860

I've never had to use this idiom and I would rather discourage it because it's a code smell of possible busy loop.
Cheers
Val
回覆所有人
回覆作者
轉寄
0 則新訊息