34

GO チュートリアルには、次のスライドがあります

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")
}

このコードを実行すると、期待どおりの結果が得られます (「world」と「hello」が交互に 5 回画面に表示されます)。

ただし、コメントアウトtime.Sleep(およびその結果、"time"インポートの行) を実行してプログラムを再度実行すると、画面に「hello」が 5 回書き込まれるだけです。

time.Sleepゴルーチンを死なせないために重要なことは何ですか?

4

3 に答える 3

13

ゴルーチン スケジューラはプリエンプティブではないため、ゴルーチンは別のゴルーチンが実行される前に制御を放棄する必要があります。コントロールを放棄する 1 つの方法は、 を使用することtime.Sleepです。別の方法はruntime.Gosched()です。

Gosched() を使用するように変更されたチュートリアルは次のとおりです: http://play.golang.org/p/jQ9mlGYXXE

これは、ゴルーチンを理解する上で役立つレッスンです。ただし、スケジューラを直接制御しようとすることは間違いなくアンチパターンです。多くの場合、悲しみが続きます。

代わりに、通信するデジタル ハードウェアの塊のようなゴルーチンについて考えてください (ステート マシンは良い例えです)。goroutine の基礎となるCommunicating Sequential Processesモデルについて学ぶことをお勧めします。CSP ベースの設計では、各ゴルーチンは独自のプライベート状態を持ち、メッセージを交換して他のゴルーチンの状態と対話します。メッセージを渡すと同期が強制され、スケジューラはこれを使用して、CPU 時間を取得するアクティビティと待機キューに入れるアクティビティを決定します。

この方法で Go にアプローチする場合、スケジューラの内部について心配する必要はおそらくないでしょう。

于 2013-04-04T21:01:00.420 に答える
2

time.Sleepを say 関数から削除すると、メインは say("hello") を実行し、ゴルーチンを実行せずに終了します。メイン エンドの前にtime.Sleep (またはselect {} ) を追加すると、ゴルーチンを実行する時間が与えられ、そのスレッドがスケジューラから選択されます。

例:

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`
}

出力は通常、5 つのhelloの後に 5 つのworldが続きますが、最後のhelloの前にworldの 1 つを印刷することもできます

やってみる --> (http://) goo.gl/K2v7H0

于 2016-06-07T23:36:23.560 に答える