ホームページ  >  記事  >  バックエンド開発  >  Golang は同時プログラミングを実装します

Golang は同時プログラミングを実装します

王林
王林オリジナル
2023-05-12 22:01:37946ブラウズ

Go 言語 (golang) は軽量の同時プログラミング言語であり、開発者が同時プログラミングを容易に扱えるように設計されています。 Golang は、同時実行性の高いプログラミング タスクを簡単に実装できる豊富な言語機能とライブラリ関数を提供します。この記事では、同時プログラミングを実装するための Golang の方法とテクニックを紹介します。

1. ゴルーチンとチャネル
ゴルーチンとチャネルは、Golang の同時プログラミングの 2 つの中心的な概念であり、Golang を使用して効率的な同時プログラムを開発するための鍵となります。ゴルーチンは Golang の軽量スレッドであり、Golang のすべての関数はゴルーチンとして実行できます。チャネルは、Goroutine 間の通信に使用されるパイプであり、これを通じて複数の Goroutine 間でデータを転送できます。

次の例は、ゴルーチンとチャネルを使用して単純な並行プログラムを実装する方法を示しています。

package main

import (
    "fmt"
    "time"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("worker", id, "started job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    for j := 1; j <= 9; j++ {
        jobs <- j
    }
    close(jobs)

    for a := 1; a <= 9; a++ {
        <-results
    }
}

上の例では、ワーカー関数はゴルーチンとして実行され、ジョブ パイプラインからタスクを取得します。処理中、結果は結果パイプラインに送信されます。 main 関数は、ジョブと結果という 2 つのパイプラインを作成し、タスクをジョブ パイプラインに送信し、最後にすべての結果が結果パイプラインから取り出されるのを待ちます。

2. WaitGroups
WaitGroups は、Golang ライブラリのもう 1 つの重要なリソースであり、Goroutine のグループが実行を完了するのを待つためのメカニズムです。ゴルーチンのグループが特定のタスクを完了するのを待つ必要がある場合は、Add、Done、および Wait の 3 つのメソッドを提供する WaitGroup を使用できます。コード内の Add メソッドは待機する必要があるゴルーチンの数を示し、Done メソッドは特定のゴルーチンがタスクを完了したことを示し、Wait メソッドはすべてのゴルーチンがタスクを完了するのをブロックして待機します。

次の例は、WaitGroup を使用して単純な同時タスクを実装する方法を示しています。

package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()

    fmt.Printf("Worker %d starting
", id)

    time.Sleep(time.Second)
    fmt.Printf("Worker %d done
", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()

    fmt.Println("All workers done")
}

上の例では、ワーカー関数は Goroutine として実行され、すべての Goroutine が WaitGroup を通じて完了するのを待ちます。 main 関数で、WaitGroup を作成し、Add メソッドを使用して待機リストに参加します。Done メソッドは、特定の Goroutine がタスクを完了したことを示します。Wait メソッドはブロックし、すべての Goroutine がタスクを完了するまで待機します。

3. Mutexes
Mutexes は、Golang ライブラリで提供されるもう 1 つの非常に重要な同時プログラミング ツールで、リソースが複数の Goroutine 間で共有される場合にデータのセキュリティを確保できます。リソースをロックおよびロック解除することで、共有リソースに同時にアクセスできるのは 1 つの Goroutine だけであることを保証できます。

次の例は、ミューテックスを使用して同時タスクを実装する方法を示しています。

package main

import (
    "fmt"
    "sync"
    "time"
)

type SafeCounter struct {
    value int
    mutex sync.Mutex
}

func (c *SafeCounter) Increment() {
    c.mutex.Lock()

    c.value++
    fmt.Println(c.value)

    c.mutex.Unlock()
}

func main() {
    counter := SafeCounter{0, sync.Mutex{}}

    for i := 0; i < 10; i++ {
        go func() {
            for {
                counter.Increment()
                time.Sleep(time.Millisecond)
            }
        }()
    }
    time.Sleep(time.Second)
}

上の例では、SafeCounter 型には変数値とミューテックス ミューテックス ロックが含まれています。 Increment メソッドは value 変数に 1 を追加します。value は共有リソースであるため、メソッド内でミューテックスをロックおよびロック解除して、同時に 1 つの Goroutine だけが value 変数にアクセスできるようにする必要があります。

4. Atomic
Atomic は、Golang ライブラリで提供されるもう 1 つの並行プログラミング ツールで、リソースが複数の Goroutine 間で共有される場合にデータのアトミック性を保証できます。アトミックは、追加、比較交換、ロード、ストア、その他のメソッドなど、CPU 命令に基づいたさまざまなアトミック操作を提供します。

次の例は、Atomic を使用して単純な同時タスクを実装する方法を示しています。

package main

import (
    "fmt"
    "sync/atomic"
    "time"
)

func main() {
    var counter int32

    for i := 0; i < 10; i++ {
        go func() {
            for {
                atomic.AddInt32(&counter, 1)
                fmt.Println(atomic.LoadInt32(&counter))
                time.Sleep(time.Millisecond)
            }
        }()
    }
    time.Sleep(time.Second)
}

上の例では、Atomic の AddInt32 メソッドと LoadInt32 メソッドを使用してカウンターを実装しています。 AddInt32 メソッドはカウンターの値を増加させ、LoadInt32 メソッドはカウンターの現在の値を取得します。これらのアトミックな操作により操作のアトミック性が保証されるため、カウンタの増分の正確性が保証されます。

5. Select
Select は、Golang のもう 1 つの非常に重要な同時プログラミング ツールで、複数のチャネルでメッセージを同時に待機するためのメカニズムであり、開発者が複雑な同時タスクを処理するのに役立ちます。 Select ステートメントでは、複数のチャネルを宣言し、いずれかのチャネルがデータを送信するのを待ってから、対応するロジックを実行できます。

次の例は、Select ステートメントを使用して単純な同時タスクを実装する方法を示しています。

package main

import (
    "fmt"
    "time"
)

func main() {
    channel1 := make(chan string)
    channel2 := make(chan string)

    go func() {
        time.Sleep(time.Second)
        channel1 <- "Hello"
    }()
    go func() {
        time.Sleep(time.Second * 2)
        channel2 <- "World"
    }()

    for i := 0; i < 2; i++ {
        select {
        case message1 := <-channel1:
            fmt.Println("Received message1", message1)
        case message2 := <-channel2:
            fmt.Println("Received message2", message2)
        }
    }
}

上の例では、main 関数で 2 つのチャネル (channel1 と channel2) が宣言されています。 2 つのゴルーチンを使用してこれら 2 つのチャネルにメッセージを送信し、メイン関数の Select を使用してメッセージの送信を待機し、特定の状況に応じて対応する情報を出力します。

結論
Golang は、Goroutines、Channels、WaitGroups、Mutexes、Atomic、Select などを含む、多くの強力な同時プログラミング ツールとライブラリを提供します。これらのツールを使用すると、効率的な同時プログラミング タスクを簡単に実装できます。並行プログラムを作成するときは、デッドロックや競合状態などの問題を回避するために、データのセキュリティと正確性の確保に注意する必要があります。

以上がGolang は同時プログラミングを実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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