ホームページ >バックエンド開発 >Golang >デコードされた Go の同時実行性: Goroutine のスケジューリング

デコードされた Go の同時実行性: Goroutine のスケジューリング

Barbara Streisand
Barbara Streisandオリジナル
2025-01-14 22:08:45724ブラウズ

Go

私。ゴルーチン: Go の同時実行モデルの詳細

ゴルーチンは Go 設計の基礎であり、同時プログラミングのための強力なメカニズムを提供します。 軽量のコルーチンとして、タスクの並列実行が簡素化されます。 goroutine の起動は簡単です。関数呼び出しの前に go キーワードを付けて、非同期実行を開始するだけです。メインプログラムはゴルーチンの完了を待たずに続行されます。

<code class="language-go">go func() { // Launch a goroutine using the 'go' keyword
    // ... code to be executed concurrently ...
}()</code>

II. Goroutine の内部メカニズムを理解する

概念的な基礎

同時実行性と並列性

  • 同時実行性: 単一の CPU 上で複数のタスクを一見同時に管理する機能。 CPU はタスク間を急速に切り替え、並列実行のような錯覚を生み出します。 微視的には連続的ですが、巨視的には同時的に見えます。

  • 並列処理: 複数の CPU にわたる複数のタスクの真の同時実行により、CPU リソースの競合が排除されます。

プロセスとスレッド

  • プロセス: 独自のリソース (メモリ、ファイルなど) を備えた自己完結型の実行環境。 プロセス間の切り替えはリソースを大量に消費するため、カーネルレベルの介入が必要です。

  • スレッド: プロセス内の軽量の実行単位であり、プロセスのリソースを共有します。 スレッド切り替えは、プロセス切り替えよりもオーバーヘッドが少なくなります。

コルーチン

コルーチンは独自のレジスタ コンテキストとスタックを維持します。 コルーチン間の切り替えには、この状態の保存と復元が含まれ、中断したところから実行を再開できるようになります。 プロセスやスレッドとは異なり、コルーチン管理はオペレーティング システムではなくユーザー プログラム内で処理されます。ゴルーチンは、特定の種類のコルーチンです。

GPM スケジューリング モデル

Go の効率的な同時実行性は、GPM スケジューリング モデルに依存しています。 M、P、G、および Sched の 4 つの主要なコンポーネントが関係します (Sched は図には示されていません)。

  • M (マシン): カーネルレベルのスレッド。ゴルーチンは

    さんで実行されます
  • G (ゴルーチン): 単一のゴルーチン。 各 G には、独自のスタック、命令ポインター、およびその他のスケジューリング関連情報 (待機しているチャネルなど) があります。

  • P (プロセッサ): ゴルーチンを管理および実行する論理プロセッサ。準備完了の goroutine の実行キューを維持します。

  • Sched (スケジューラ): M キューと G キューを管理し、効率的なリソース割り当てを保証する中央スケジューラ。

実際のスケジュール設定

Go

この図は、ゴルーチンを実行するプロセッサ (P) を備えた 2 つの OS スレッド (M) を示しています。

  • GOMAXPROCS() は P の数 (つまり、実際の同時実行レベル) を制御します。

  • 灰色の G は準備ができていますが、まだ実行されていません。 P はこの実行キューを管理します。

  • ゴルーチンを起動すると、P の実行キューに追加されます。

Go

M0 がブロックされている場合、P は M1 (スレッド キャッシュから取得される可能性があります) に切り替わります。

Go

P がタスクを迅速に完了すると、効率を維持するために他の P から仕事を盗む可能性があります。

III.ゴルーチンの操作

基本的な使い方

ゴルーチン実行用の CPU の数を設定します (通常、最近の Go バージョンのデフォルト設定で十分です):

<code class="language-go">go func() { // Launch a goroutine using the 'go' keyword
    // ... code to be executed concurrently ...
}()</code>

実践的な例

例 1: 単純なゴルーチンの計算

<code class="language-go">num := runtime.NumCPU() // Get the number of logical CPUs
runtime.GOMAXPROCS(num) // Set the maximum number of concurrently running goroutines</code>

ゴルーチンのエラー処理

ゴルーチン内の未処理の例外により、プログラム全体が終了する可能性があります。パニックを処理するには、recover() ステートメント内で defer を使用します。

<code class="language-go">package main

import (
    "fmt"
    "runtime"
)

func cal(a, b int) {
    c := a + b
    fmt.Printf("%d + %d = %d\n", a, b, c)
}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    for i := 0; i < 10; i++ {
        go cal(i, i+1)
    }
    //Note:  The main function exits before goroutines complete in this example.  See later sections for synchronization.
}</code>

ゴルーチンの同期

ゴルーチンは非同期で実行されるため、メインプログラムは完了する前に終了する可能性があります。 同期には sync.WaitGroup またはチャネルを使用します:

例 1: sync.WaitGroup

の使用
<code class="language-go">package main

import (
    "fmt"
)

func addele(a []int, i int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Error in addele:", r)
        }
    }()
    a[i] = i // Potential out-of-bounds error if i is too large
    fmt.Println(a)
}

func main() {
    a := make([]int, 4)
    for i := 0; i < 5; i++ {
        go addele(a, i)
    }
    // ... (add synchronization to wait for goroutines to finish) ...
}</code>

例 2: 同期にチャネルを使用する

<code class="language-go">package main

import (
    "fmt"
    "sync"
)

func cal(a, b int, wg *sync.WaitGroup) {
    defer wg.Done()
    c := a + b
    fmt.Printf("%d + %d = %d\n", a, b, c)
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go cal(i, i+1, &wg)
    }
    wg.Wait()
}</code>

Goroutine 間通信

チャネルは、ゴルーチン間の通信とデータ共有を容易にします。 グローバル変数も使用できますが、同時実行性の制御を向上させるには、一般にチャネルの使用が推奨されます。

例: 生産者と消費者のパターン

<code class="language-go">package main

import (
    "fmt"
)

func cal(a, b int, ch chan bool) {
    c := a + b
    fmt.Printf("%d + %d = %d\n", a, b, c)
    ch <- true // Signal completion
}

func main() {
    ch := make(chan bool, 10) // Buffered channel to avoid blocking
    for i := 0; i < 10; i++ {
        go cal(i, i+1, ch)
    }
    for i := 0; i < 10; i++ {
        <-ch // Wait for each goroutine to finish
    }
}</code>

Leapcell: Go 用のサーバーレス プラットフォーム

Leapcell は、Go サービスを展開するための推奨プラットフォームです。

Go

主な機能:

  1. 多言語サポート: JavaScript、Python、Go、Rust。
  2. 無料無制限プロジェクト: 従量課金制の価格設定。
  3. 費用対効果の高い: アイドル料金はかかりません。
  4. 開発者向け: 直感的な UI、自動化された CI/CD、リアルタイム メトリクス。
  5. スケーラブルで高性能: 自動スケーリング、運用オーバーヘッドなし。

Go

ドキュメントで詳細を確認してください!

リープセル Twitter: https://www.php.cn/link/7884effb9452a6d7a7a79499ef854afd

以上がデコードされた Go の同時実行性: Goroutine のスケジューリングの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。