# Rob Pike のコア開発者がこのトピックについて具体的に言及しました (推奨学習: go
)
for ループで goroutine を作成するために go を使用しますが、変数をループするたびに、golang が確実にこの goroutine を実行し、その時点で変数を出力することは当然のことだと考えています。 この時、私たちは固定観念に陥っていました。デフォルトの同時実行性は並列処理と同じです。
確かに、go で作成された goroutine は関数コードを同時に実行します。
しかし、想像どおりループするたびに実行されるのでしょうか?答えは否定です。
Rob Pike は、golang の同時実行性とは、コード構造内の特定の関数が論理的には同時に実行できるが、物理的には同時に実行できない可能性があるという事実を指すと特に述べました。並列処理とは、物理レベルで異なるタスクまたは同じタスクを実行するために異なる CPU を使用することを指します。Golang の goroutine スケジューリング モデルは、各 goroutine が仮想 CPU (つまり、runtime.GOMAXPROCS(1) で設定した仮想 CPU の数) で実行されることを決定します。 仮想 CPU の数は、実際の CPU の数と一致しない場合があります。各ゴルーチンは特定の P (仮想 CPU) によって選択および維持され、M (物理コンピューティング リソース) は毎回有効な P を選択し、P でゴルーチンを実行します。
各 P は、維持する goroutine を G キューに入れます。G キューには、Goroutine スタック情報、実行可能情報などが含まれます。デフォルトでは、P の数は実際の物理 CPU の数と同じです。
したがって、ループを通じてゴルーチンを作成すると、各ゴルーチンは異なる P キューに割り当てられます。 M の数は一意ではなく、M が P をランダムに選択することは、ゴルーチンをランダムに選択することと同じです。
この質問では、P=1 に設定します。したがって、すべてのゴルーチンは同じ P にバインドされます。 runtime.GOMAXPROCS の値を変更すると、別の順序が表示されます。 goroutine ID を出力すると、ランダム選択の効果がわかります。
func main() { wg := sync.WaitGroup{} wg.Add(20) for i := 0; i < 10; i++ { go func() { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } fmt.Println("go routine 1 i: ", i, id) wg.Done() }() } for i := 0; i < 10; i++ { go func(i int) { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } fmt.Println("go routine 2 i: ", i, id) wg.Done() }(i) } wg.Wait() }出力は次のとおりです。
go routine 2 i: 9 24 go routine 1 i: 10 11 go routine 1 i: 10 5 go routine 1 i: 10 6 go routine 2 i: 3 18 go routine 1 i: 10 9 go routine 1 i: 10 10 go routine 1 i: 10 8 go routine 2 i: 0 15 go routine 2 i: 4 19 go routine 2 i: 6 21 go routine 1 i: 10 7 go routine 1 i: 10 14 go routine 2 i: 7 22 go routine 2 i: 8 23 go routine 1 i: 10 13 go routine 2 i: 5 20 go routine 1 i: 10 12 go routine 2 i: 1 16 go routine 2 i: 2 17 ⋊> ~/S/g/g/s/t/C/goroutine ./goroutine go routine 1 i: 10 11 go routine 2 i: 9 24 go routine 1 i: 10 6 go routine 1 i: 10 14 go routine 1 i: 10 9 go routine 1 i: 10 10 go routine 1 i: 10 12 go routine 2 i: 0 15 go routine 1 i: 10 13 go routine 1 i: 10 5 go routine 2 i: 1 16 go routine 2 i: 5 20 go routine 1 i: 10 7 go routine 2 i: 7 22 go routine 2 i: 3 18 go routine 2 i: 2 17 go routine 2 i: 4 19 go routine 1 i: 10 8 go routine 2 i: 8 23 go routine 2 i: 6 21
この質問にもう一度戻りますが、ループ内 goroutine は go によって定義されます。しかし、前述したように、同時実行性は並列性を意味するものではありません。したがって、定義されていても、現時点では実装されていない可能性があります。 ゴルーチンを実行する前に、M が P を選択するまで待つ必要があります。 goroutine が golang (GPM モデル) でどのようにスケジュールされるかについては、Scalable Go Scheduler Design Doc または LearnConcurrency
を参照してください。以上がgolang の同時実行は並列処理ではありませんの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。