Search code examples
gogoroutine

Does using `runtime.Gosched()` in the default case of a Select statement make any sense?


Go's documentation says that

Gosched yields the processor, allowing other goroutines to run. It does not suspend the current goroutine, so execution resumes automatically.

Based on that definition if I have a series of long running go routines being created and executed concurrently, would it be advantageous to write a select statement the following way:

for {
    select {
        case msg := <- msgch : 
            fmt.Println(msg)
        default: 
            runtime.Gosched()
    }
} 

I assume based on the documentation, this code can result in more go routines being run. Is my assumption correct?


Solution

  • No, it isn't necessary here, because whenever Go is waiting on a channel or waiting for I/O, it allows other goroutines to run automatically. That's been the case since Go 1.0.

    In Go 1.2 the Go runtime's scheduler added automatic preemption points whenever you called a function. Prior to that if you had a CPU-bound loop (even with a function call) it could starve the scheduler and you might need runtime.Gosched.

    And then in Go 1.14, they made this aspect of the runtime even better, and even tight CPU-bound loops with no functions calls are automatically pre-empted.

    So with any Go version, you don't need to call runtime.Gosched when you're just waiting on a channel or on I/O; before 1.14, you may have wanted to call it if you were doing a long-running calculation. But with Go 1.14+, I don't see why you'd ever need to call it manually.


    If I was reviewing your actual code, I'd suggest changing it to a simple for ... range loop:

    for msg := range msgCh {
        fmt.Println(msg)
    }
    

    This will wait for each message to come in and print it, and stop if/when the channel is closed. However, you would want a switch if you're waiting on another channel or done signal, for example a context. Something like this:

    for {
        select {
            case msg := <- msgCh:
                fmt.Println(msg)
            case <-ctx.Done():
                return
        }
    }