0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go | errgroup.Group に至るまで

Last updated at Posted at 2024-08-01

雑めも

  • errgroup.Group を使っているけど、より原理的に書くとどうなるか整理
  • 逆にいうと原理的に書くスタイルから、どうブラッシュアップされていくかみてみる

sync.WaitGroup

  • Playgound
  • 実行完了の制御として sync.WaitGroup を使う
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup // 実行完了の制御用

	for i := range 5 { // 非同期N回実行
		wg.Add(1) // increment
		go func() {
			defer wg.Done() // decrement
			fmt.Printf("i is %s\n", i)
		}()
	}

	wg.Wait() // wait
}

sync.WaitGroup + chan を使った最大数制御

  • Playground
  • 自前で実行最大数を制御するためのchan を使う
package main

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

func main() {
	var wg sync.WaitGroup //実行完了の制御

+	// 最大数の制御
+	const max = 2
+	sem := make(chan bool, max)

	for i := range 5 { // 非同期N回実行
		wg.Add(1)   // increment
		go func() {
+      		sem <- true // channelの長さに空きがないと値を送れなくて、channel に入れられるまでwaitできる.
			defer wg.Done()          // decrement
+			defer func() { <-sem }() // 実行後に値を破棄する
			fmt.Printf("i is %s\n", i)
		}()
	}
	wg.Wait()
}

sync.WaitGroup + semaphore を使った最大数制御

  • Playgound
  • 最大数の制御を自前のchanから、抽象化されたsemaphore に差し替え
package main

import (
+	"context"
	"fmt"
	"sync"
	"time"

+	"golang.org/x/sync/semaphore"
)

func main() {
	ctx := context.TODO()
	var wg sync.WaitGroup //実行完了の制御

	// 最大数の制御
	const max = 2
-    sem := make(chan bool, max)
+    sem := semaphore.NewWeighted(max)

	for i := range 5 { // 非同期N回実行
		wg.Add(1) // increment
		go func() {
-           sem <- true // channelの長さに空きがないと値を送れなくて、channel に入れられるまでwaitできる.	
+			if err := sem.Acquire(ctx, 1); err != nil { // 1つ分の領域確保
+				fmt.Println("something wrong with sem.Acquire")
+				return
+			}
			defer wg.Done()      // decrement
-           defer func() { <-sem }() // 実行後に値を破棄する	
+			defer sem.Release(1) // 1つ分の領域解放
			fmt.Printf("i is %s\n", i)
		}()
	}
	wg.Wait()
}

errgroup.Group

  • Playground
  • 実行完了の制御、最大数の制御、エラーハンドリングをまとめて errgroup.Group にて行う
package main

import (
	"context"
	"fmt"

	"golang.org/x/sync/errgroup"
)

func main() {
	ctx := context.TODO()

	eg, _ := errgroup.WithContext(ctx)
	eg.SetLimit(2) // 最大数の制御

	for i := range 5 { // 非同期N回実行
		eg.Go(func() error {
			fmt.Printf("i is %s\n", i)
			return nil
		})
	}
	if err := eg.Wait(); err != nil {
		panic(err)
	}
}


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?