質問

In the GO tutorial, we have this slide: Goroutines

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

Running this code produces expected results ("world" and "hello" written to the screen interchangeably 5 times).

However, if we comment out time.Sleep (and consequently, the "time" line of the import) and run the program again, we are left with only "hello" written to the screen five times.

What is so important about time.Sleep that saves the goroutine from dying?

役に立ちましたか?

解決

If you remove the time.Sleep you don't give the say("world") goroutine a chance to run. The goroutine scheduler is not preemptive. Your goroutines have to give up control before another goroutine will run. One way to give up control is to run time.Sleep.

If you take out the time.Sleep from the say function then the primary goroutine runs 5 times without giving up control to the secondary goroutine and then when the primary goroutine returns from say the program exits because there is nothing to keep the program alive.

他のヒント

Because the goroutine scheduler is not preemptive, your goroutines have to give up control before another goroutine will run. One way to give up control is with time.Sleep. Another way is with runtime.Gosched().

Here's the tutorial modified to use Gosched(): http://play.golang.org/p/jQ9mlGYXXE

This is a useful lesson in understanding goroutines. However, trying to control the scheduler directly is definitely an anti-pattern; grief will often follow.

Instead, think more about the goroutines like chunks of communicating digital hardware (state machines are a good analogy). It's better to learn about the Communicating Sequential Processes model on which goroutines are based. In a CSP-based design, each goroutine has its own private state and exchanges messages to interact with the state of other goroutines. The passing of messages forces synchronization, which the scheduler uses to determine what activity gets cpu time and what gets put in a wait queue.

When you approach Go this way, you probably never need to worry about scheduler internals.

If you remove time.Sleep from the say function the main will execute say("hello") and terminate without executing the goroutine. If you add a time.Sleep (or otherwise a select {}) before the main end it will give time to the goroutine to run and that thread will be picked from the scheduler.

Example:

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        // time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")

    time.Sleep(1*time.Second)
    // Vs: 
    // select {} // blocks indefinitely, requires manual interrupt
          // In CSP-speak the empty select is like STOP.
          // for{} would cause the cpu to max and the process's STATE will be `running`
          // select{} will not cause the cpu to max and the process state will be `sleeping`
}

The output will usually be 5 hello followed by 5 world but it could also manage to print one of the world before the last hello

TRY IT --> (http://) goo.gl/K2v7H0

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top