ホームページ > バックエンド開発 > Golang > Go 同時実行性: ミューテックスとチャネルの例

Go 同時実行性: ミューテックスとチャネルの例

Mary-Kate Olsen
リリース: 2025-01-08 20:10:54
オリジナル
539 人が閲覧しました

Go 同時プログラミングにおけるカウンター同期: ミューテックス、バッファー付きチャネル、およびバッファーなしチャネル

Go で同時アプリケーションを構築する場合、共有データへの安全なアクセスを確保するために同期が重要です。 MutexChannel は、Go の同期のための主要なツールです。

この記事では、安全な同時実行カウンターを構築するいくつかの方法を検討します。参考記事では Mutex を使用してこの問題を解決していますが、バッファ付きチャネルとバッファなしチャネルを使用した代替案も検討します。

問題の説明

安全に同時に使用できるカウンターを構築する必要があります。

カウンターコード

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

type Counter struct {
    count int
}

func (c *Counter) Inc() {
    c.count++
}

func (c *Counter) Value() int {
    return c.count
}</code>
ログイン後にコピー

コードの同時実行性を安全にするために、いくつかのテストを書いてみましょう。

1. ミューテックスを使用します

Mutex (ミューテックス) は、一度に 1 つのゴルーチンだけがコードの重要な部分にアクセスできるようにする同期プリミティブです。これはロックメカニズムを提供します。ゴルーチンが Mutex をロックすると、それをロックしようとする他のゴルーチンは Mutex がロック解除されるまでブロックされます。したがって、共有変数またはリソースを競合状態から保護する必要がある場合によく使用されます。

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

import (
    "sync"
    "testing"
)

func TestCounter(t *testing.T) {
    t.Run("using mutexes and wait groups", func(t *testing.T) {
        counter := Counter{}
        wantedCount := 1000

        var wg sync.WaitGroup
        var mut sync.Mutex

        wg.Add(wantedCount)

        for i := 0; i < wantedCount; i++ {
            go func() {
                defer wg.Done()
                mut.Lock()
                counter.Inc()
                mut.Unlock()
            }()
        }

        wg.Wait()
        if counter.Value() != wantedCount {
            t.Errorf("got %d, want %d", counter.Value(), wantedCount)
        }
    })
}</code>
ログイン後にコピー

このコードは、sync.WaitGroup を使用してすべてのゴルーチンの完了を追跡し、sync.Mutex を使用して複数のゴルーチンが共有カウンターに同時にアクセスすることを防ぎます。

2. バッファチャネルを使用します

Go Concurrency: Mutexes vs Channels with Examples

チャネルは、Go が goroutine が安全に通信できるようにする方法です。これらはゴルーチン間でデータを転送し、渡されたデータへのアクセスを制御することで同期を提供できます。

この例では、チャネルを使用して goroutine をブロックし、1 つの goroutine のみが共有データにアクセスできるようにします。バッファリングされたチャネルの容量は固定されており、送信者をブロックする前に事前定義された数の要素を保持できることを意味します。送信者はバッファがいっぱいの場合にのみブロックします。

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

import (
    "sync"
    "testing"
)

func TestCounter(t *testing.T) {
    t.Run("using buffered channels and wait groups", func(t *testing.T) {
        counter := Counter{}
        wantedCount := 1000

        var wg sync.WaitGroup
        wg.Add(wantedCount)

        ch := make(chan struct{}, 1)

        ch <- struct{}{} // 允许第一个 goroutine 开始

        for i := 0; i < wantedCount; i++ {
            go func() {
                defer wg.Done()
                <-ch
                counter.Inc()
                ch <- struct{}{}
            }()
        }

        wg.Wait()
        if counter.Value() != wantedCount {
            t.Errorf("got %d, want %d", counter.Value(), wantedCount)
        }
    })
}</code>
ログイン後にコピー

このコードは容量 1 のバッファリングされたチャネルを使用し、一度に 1 つの goroutine のみがカウンターにアクセスできるようにします。

3. バッファリングされていないチャネルを使用する

Go Concurrency: Mutexes vs Channels with Examples

バッファなしチャンネルにはバッファがありません。受信側がデータを受信する準備ができるまで、送信側をブロックします。これにより、ゴルーチン間で一度に 1 つずつデータが受け渡される厳密な同期が提供されます。

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

import (
    "sync"
    "testing"
)

func TestCounter(t *testing.T) {
    t.Run("using unbuffered channels and wait groups", func(t *testing.T) {
        counter := Counter{}
        wantedCount := 1000

        var wg sync.WaitGroup
        wg.Add(wantedCount)

        ch := make(chan struct{})

        go func() {
            for i := 0; i < wantedCount; i++ {
                ch <- struct{}{}
            }
            close(ch)
        }()

        for range ch {
            counter.Inc()
            wg.Done()
        }

        if counter.Value() != wantedCount {
            t.Errorf("got %d, want %d", counter.Value(), wantedCount)
        }
    })
}
</code>
ログイン後にコピー

このコードはバッファリングされていないチャネルを使用して、一度に 1 つの goroutine だけがカウンターにアクセスできるようにします。

4. WaitGroup の代わりにバッファ チャネルを使用します

WaitGroup なしでバッファリングされたチャネルを使用することもできます。たとえば、無限ループや別のチャネルを使用してゴルーチンの完了を追跡することができます。

結論

この記事では、Go で安全な同時実行カウンターを構築するためのさまざまなアプローチを検討します。これらのツールとそれらをいつ使用するかを理解することが、効率的で安全な同時実行 Go プログラムを作成するための鍵となります。

参考リソース

この記事は、「テストで Go を学ぶ」の同期の章からインスピレーションを受けています。

この記事がお役に立てば幸いです!

以上がGo 同時実行性: ミューテックスとチャネルの例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート