Skip to content

Go言語による並行処理 読書ログ

2023/02/18

Go

目次

目次

  1. 1 章 並行処理入門
    1. 1.1 ムーアの法則、Web スケール、そして私たちのいる混沌
    2. 1.2 なぜ並行処理が難しいのか
    3. 1.2.1  競合状
    4. 1.2.2  アトミック性
    5. 1.2.3 メモリアクセス同期
    6. 1.2.4  デッドロック、ライブロック、リソース枯渇
    7. 1.2.5 並行処理の安全性を見極める
    8. 1.3 複雑さを前にした簡潔さ
  2. 2 章 並行性をどうモデル化するか:CSP とは何か
    1. 2.1  並行性と並列性の違い
    2. 2.2 CSP とは何か
    3. 2.3 これがどう役に立つのか
    4. 2.4 Go の並行処理における哲学
  3. 3 章  Go における並行処理の構成要素
    1. 3.1 ゴルーチン(goroutine)
    2. 3.2 sync パッケージ
    3. 3.3 チャネル(channel)
    4. 3.4 select 文
    5. 3.5 GOMAXPROCS レバー
    6. 3.6  まとめ
  4. 4 章 Go での並行処理パターン
    1. 4.1  拘束
    2. 4.2 for-select ループ
    3. 4.3 ゴルーチンリークを避ける
    4. 4.4 or チャネル
    5. 4.5 エラーハンドリング
    6. 4.6 パイプライン
    7. 4.7 ファンアウト、ファンイン
    8. 4.8 or-done チャネル
    9. 4.9 tee チャネル
    10. 4.10 bridge チャネル
    11. 4.13 まとめ

1 章 並行処理入門

1.1 ムーアの法則、Web スケール、そして私たちのいる混沌

1.2 なぜ並行処理が難しいのか

1.2.1  競合状

1.2.2  アトミック性

1.2.3 メモリアクセス同期

1.2.4  デッドロック、ライブロック、リソース枯渇

1.2.5 並行処理の安全性を見極める

1.3 複雑さを前にした簡潔さ

2 章 並行性をどうモデル化するか:CSP とは何か

2.1  並行性と並列性の違い

2.2 CSP とは何か

2.3 これがどう役に立つのか

2.4 Go の並行処理における哲学

Yes
No
Yes
No
Yes
No
No
Yes
パフォーマンスクリティカルセクションか?
プリミティブを使う
データの所有権を移動しようとしているか?
チャネルを使う
構造体の内部の状態を保護しようとしているか?
複数のロジックを協調させようとしているか?

3 章  Go における並行処理の構成要素

3.1 ゴルーチン(goroutine)

3.2 sync パッケージ

wg.Add(1)
go func() {
    defer wg.Done()
    fmt.Println("1st goroutine sleeping...")
    time.Sleep(1)
}()

wg.Add(1)
go func() {
    defer wg.Done()
    fmt.Println("2nd goroutine sleeping...")
    time.Sleep(2)”

}()

wg.Wait()
fmt.Println("All goroutines complete.")”

// 2nd goroutine sleeping...
// 1st goroutine sleeping...
// All goroutines complete.”
// sleepでCPUを待機させる
for conditionTrue() == false {
    time.Sleep(1*time.Millisecond)
}

// Waitで別のごルーチンを待機させる
c := sync.NewCond(&sync.Mutex{})
c.L.Lock()
for conditionTrue() == false {
    c.Wait()
}
c.L.Unlock()

3.3 チャネル(channel)

3.4 select 文

3.5 GOMAXPROCS レバー

3.6  まとめ

4 章 Go での並行処理パターン

4.1  拘束

chanOwner := func() <-chan int {
    results := make(chan int, 5)
    go func() {
        defer close(results)
        for i := 0; i <= 5; i++ {
            results <- i
        }
    }()
    return results
}

consumer := func(results <-chan int) {
    for result := range results {
        fmt.Printf("Received: %d\n", result)
    }
    fmt.Println("Done receiving!")
}

results := chanOwner()
consumer(results)

4.2 for-select ループ

4.3 ゴルーチンリークを避ける

doWork := func(
  done <-chan interface{},
  strings <-chan string,
) <-chan interface{} {
    terminated := make(chan interface{})
    go func() {
        defer fmt.Println("doWork exited.")
        defer close(terminated)
        for {
            select {
            case s := <-strings:
                 fmt.Println(s)
            case <-done:
                return
            }
        }
    }()
    return terminated
}

done := make(chan interface{})
terminated := doWork(done, nil)

go func() {
    time.Sleep(1 * time.Second)
    fmt.Println("Canceling doWork goroutine...")
    close(done)
}()

<-terminated
fmt.Println("Done.")

// Canceling doWork goroutine...
// doWork exited.
// Done.

4.4 or チャネル

4.5 エラーハンドリング

4.6 パイプライン

4.7 ファンアウト、ファンイン

4.8 or-done チャネル

4.9 tee チャネル

4.10 bridge チャネル

4.13 まとめ