Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this select always run the default case when the first case actually is executed?

I'm trying to get a better understanding of golang channels. While reading this article I'm toying with non-blocking sends and have come up with the following code:

package main
import (
    "fmt"
    "time"
)

func main() {
    stuff := make(chan int)
    go func(){
        for i := 0; i < 5; i ++{
            select {
            case stuff <- i:
                fmt.Printf("Sent %v\n", i)
            default:
                fmt.Printf("Default on %v\n", i)
            }
        }
        println("Closing")
        close(stuff)
    }()
    time.Sleep(time.Second)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
    fmt.Println(<-stuff)
}

This will print:

Default on 0
Default on 1
Default on 2
Default on 3
Default on 4
Closing
0
0
0
0
0

While I do understand that only 0s will get printed I do not really understand why the first send does still trigger the default branch of the select?

What is the logic behind the behavior of a select in this case?

Example at the Go Playground

like image 258
m90 Avatar asked Aug 01 '17 19:08

m90


People also ask

What happens if you write default in switch case first?

The position of default doesn't matter, it is still executed if no match found. // The default block is placed above other cases.

Is default always executed in switch Java?

Is default always executed in switch Java? If there is no corresponding case value, the default clause is executed. If no case matched and there is no default clause, execution continues after the end of the switch statement.

Is it necessary to include default case in a switch statement justify?

No it is not necessary of default case in a switch statement and there is no rule of keeping default case at the end of all cases it can be placed at the starting andd middle of all other cases.

Should default be the last statement in a switch case block?

A 'switch' statement should have 'default' as the last label. Adding a 'default' label at the end of every 'switch' statement makes the code clearer and guarantees that any possible case where none of the labels matches the value of the control variable will be handled.


1 Answers

You never send any values to stuff, you execute all the default cases before you get to any of the receive operations in the fmt.Println statements. The default case is taken immediately if there is no other operation than can proceed, which means that your loop will execute and return as quickly as possible.

You want to block the loop, so you don't need the default case. You don't need the close at the end either, because you're not relying on the closed channel unblocking a receive or breaking from a range clause.

stuff := make(chan int)
go func() {
    for i := 0; i < 5; i++ {
        select {
        case stuff <- i:
            fmt.Printf("Sent %v\n", i)
        }
    }
    println("Closing")
}()
time.Sleep(time.Second)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)

https://play.golang.org/p/k2rmRDP38f

Notice also that the last "Sent" and the "Closing" line aren't printed, because you have no other synchronization waiting for the goroutine to finish, however that doesn't effect the outcome of this example.

like image 200
JimB Avatar answered Nov 15 '22 10:11

JimB