ホームページ >バックエンド開発 >Golang >Go言語の同時実行モードと並列コンピューティングをマスターする

Go言語の同時実行モードと並列コンピューティングをマスターする

王林
王林オリジナル
2023-11-30 09:30:33783ブラウズ

Go言語の同時実行モードと並列コンピューティングをマスターする

インターネットの急速な発展に伴い、大規模分散システムに対する需要はますます高まっており、同時プログラミングと並列コンピューティングはインターネット開発者が習得しなければならないスキルとなっています。 Go 言語は同時実行をサポートするために生まれた言語であり、同時プログラミングと並列コンピューティングで非常に優れたパフォーマンスを発揮します。この記事では、Go 言語の同時実行モードと並列コンピューティングを紹介し、読者が深く理解できるようにいくつかの実践的なケースを示します。

1. Go 言語の同時実行モード

Go 言語の同時実行モードは、主に goroutine とチャネルの 2 つの基本コンポーネントに基づいています。 Goroutine は軽量のスレッドで、Go 言語のランタイム システムによって管理され、go キーワードを通じて開始でき、Goroutine はチャネルを通じて通信できます。

次は、ゴルーチンとチャネルの簡単な例です。

package main

import "fmt"

func printMsg(msg string, ch chan string) {
    ch <- msg
}

func main() {
    ch := make(chan string)
    msgs := []string{"Hello", "Golang", "Parallel"}

    for _, msg := range msgs {
        go printMsg(msg, ch)
    }

    for i := 0; i < len(msgs); i++ {
        fmt.Println(<-ch)
    }
}

コードは、for ループを通じて 3 つのゴルーチンを開始し、それぞれ 3 つの文字列を出力します。 printMsg 関数は文字列メッセージをチャネルに書き込み、main 関数は再びチャネルから読み取ります。

1.1 パイプライン モード

Go 言語では、パイプライン モードを通じて複数のゴルーチンを直列に接続して、より複雑な同時システムを形成できます。パイプライン パターンの実装は通常、複数のゴルーチン間のチャネル通信を通じて行われ、あるゴルーチンから別のゴルーチンにデータを渡し、各ゴルーチンでデータを処理および変換します。以下は簡単なパイプライン モードの例です:

package main

import (
    "fmt"
)

func addOne(in <-chan int, out chan<- int) {
    for val := range in {
        out <- val + 1
    }
    close(out)
} 

func printNums(out <-chan int) {
    for val := range out {
        fmt.Println(val)
    }
}

func main() {    
    nums := []int{1, 2, 3}
    in := make(chan int)
    out := make(chan int)

    go addOne(in, out)

    go printNums(out)

    for _, num := range nums {
        in <- num
    }
    close(in)
}

コード パスは 3 つのゴルーチン、つまり入力ゴルーチン、および 1 つの処理ゴルーチンと出力ゴルーチンを定義します。addOne 関数は、入力チャネルのデータに 1 を加算して書き込みます。チャネルでは、printNums 関数が出力チャネルからデータを読み取り、出力します。

1.2 選択パターン

Go 言語の select ステートメントは、複数のチャネルを扱うための便利な方法、つまり選択パターン (select pattern) を提供します。選択モードを使用すると、複数のチャネルでノンブロッキング選択操作を実行でき、複数のチャネルに読み取りまたは書き込み可能なメッセージがある場合、そのうちの 1 つが自動的に選択されて操作されます。

以下は簡単な選択モードの例です:

package main

import "fmt"

func ping(ch chan<- string) {
    for {
        ch <- "ping"
    }
}

func pong(ch chan<- string) {
    for {
        ch <- "pong"
    }
}

func printer(ch <-chan string) {
    for {
        fmt.Println(<-ch)
    }
}

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    ch3 := make(chan string)

    go ping(ch1)
    go pong(ch2)
    go printer(ch3)

    for {
        select {
        case msg := <-ch1:
            ch3 <- msg
        case msg := <-ch2:
            ch3 <- msg
        }
    }
}

コードでは、ping 関数と pong 関数がそれぞれ ch1 と ch2、およびプリンターに「ping」と「pong」メッセージを送信します。関数はch3のメッセージを読み出して出力します。 main関数ではselect文でch1とch2のメッセージを監視し、受信したメッセージをch3経由でプリンタ関数に渡して出力します。

2. Go 言語の並列コンピューティング

Go 言語の組み込み並列コンピューティング モジュールには、同期、アトミック、コンテキストなどが含まれます。 sync と atomic は主にミューテックス (Mutex) とアトミック操作 (アトミック操作) を使用して同時データアクセスを制御し、コンテキストはゴルーチンのコンテキスト情報を管理するために使用されます。これらのモジュールの使用方法を簡単に紹介します。

2.1 ミューテックス ロック

ミューテックス ロックは、共有リソースを保護するために最も一般的に使用される同期メカニズムの 1 つであり、最もよく使用される同期メカニズムでもあります。 Go 言語の基本的な同期メカニズム。 Go 言語では、同期パッケージの Mutex タイプを使用してミューテックス ロックを作成できます。 Mutex タイプは、Lock と Unlock という 2 つの重要なメソッドを提供します。共有リソースにアクセスする前に、Lock メソッドを呼び出してロックを取得し、アクセスの完了後に Unlock メソッドを呼び出してロックを解放する必要があります。以下はミューテックス ロックの簡単な例です:

package main

import (
    "fmt"
    "sync"
)

func addOne(num *int, mutex *sync.Mutex, wg *sync.WaitGroup) {
    mutex.Lock()
    *num += 1
    mutex.Unlock()

    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    var num int

    mutex := &sync.Mutex{}
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go addOne(&num, mutex, &wg)
    }

    wg.Wait()
    fmt.Println(num)
}

コードでは、addOne 関数は num 変数に 1 を追加するように定義されています。1 を追加する前に、最初にミューテックス ロックを取得し、その後にミューテックス ロックを取得する必要があります。 1を加えると、ミューテックスロックを解除する必要があります。 WaitGroup を使用して、すべてのゴルーチンが実行を完了し、最終結果を出力するのを待ちます。

2.2 アトミック操作

同時実行性が高いシナリオでは、ミューテックス ロックによってプログラムのパフォーマンスが低下する可能性があるため、Go 言語はミューテックス ロックを置き換えるアトミック操作を提供します。アトミック パッケージは、AddInt64、CompareAndSwapInt64、SwapInt64 など、いくつかのアトミック操作関数を提供します。アトミック操作を使用すると、変数に対する操作が他のゴルーチンによって中断されず、同時実行が影響を受けなくなります。以下は簡単なアトミック操作の例です:

package main

import (
    "fmt"
    "sync/atomic"
)

func addOne(num *int64, count *int64, done chan bool) {
    for i := 0; i < 1000; i++ {
        atomic.AddInt64(num, 1)
    }
    atomic.AddInt64(count, 1)
    done <- true
}

func main() {
    var num int64
    var count int64
    done := make(chan bool)

    for i := 0; i < 100; i++ {
        go addOne(&num, &count, done)
    }

    for i := 0; i < 100; i++ {
        <-done
    }

    fmt.Printf("num=%d, count=%d
", num, count)
}

コードでは、アトミック パッケージの AddInt64 関数を使用して、num 変数に対してアトミック操作が実行されます。操作が完了すると、メイン スレッドは次の方法で通知されます。終わり。通常のAddInt64関数を通じてcount変数を累積し、最終的にnumとcountの値を出力します。

2.3 コンテキスト管理

Go 言語では、リクエスト ID やタイムアウト設定などのコンテキスト情報を複数のゴルーチン間で渡すことが必要になることがよくあります。 context パッケージは、Goroutine コンテキスト情報を管理する便利な方法を提供します。コンテキストを使用する場合、通常はメインのゴルーチン内に親コンテキストを作成する必要がありますが、ゴルーチンの導出時にはWithCancel、WithDeadline、WithValueなどの関数を使用して子コンテキストを作成し、対応するコンテキスト情報を渡します。以下は、単純なコンテキスト管理の例です。

package main

import (
    "context"
    "fmt"
    "time"
)

func worker(ctx context.Context, id int) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("worker %d canceled
", id)
            return
        default:
            fmt.Printf("worker %d is working
", id)
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())

    for i := 0; i < 3; i++ {
        go worker(ctx, i)
    }

    time.Sleep(5 * time.Second)

    cancel()
}

コードでは、コンテキスト パッケージを使用して親コンテキストを作成し、WithCancel 関数を使用して子コンテキストを作成します。ワーカー関数では、select ステートメントを使用して ctx.Done() のシグナルをリッスンします。ctx.Done() が閉じられると、コンテキストがキャンセルされ、ワー​​カー関数を終了する必要があることを意味します。 main 関数で、cancel 関数を使用してサブコンテキストを閉じ、サブコンテキストがキャンセルされるのを待ちます。実行結果は次のとおりです。

worker 0 is working
worker 1 is working
worker 2 is working
worker 2 canceled
worker 1 canceled
worker 0 canceled

親コンテキストがキャンセルされると、すべての子コンテキストが通知を受け取り、実行を終了します。

3.結論

この記事では、Go 言語の同時実行モードと並列コンピューティングを簡単に紹介し、ゴルーチン、チャネル、ミューテックス ロック、アトミック操作、コンテキストなどの基本的なコンポーネントとモジュールを紹介します。これらの基本知識を学ぶことで、Go 言語の同時実行性と並列プログラミングをより適切に習得し、高性能で同時実行性の高いインターネット アプリケーションを構築するための基礎を築くことができます。

以上がGo言語の同時実行モードと並列コンピューティングをマスターするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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