Goの並行処理でchannelを使う

https://isehara-3lv.sakura.ne.jp/blog/2023/01/12/goの並行処理/

ではWaitGroup使って終了を判定しましたが、Go独自の機能にスレッド間での通信機能channelを使う方法もあります。どちらが良いというのではなくて、目的によって使い分けするんだと思いますが。

以下はリンクの処理と同じく一千万までの素数を求める処理です。40行目付近から下のループ処理でchannelを使って素数をスライスに格納しています。channelが存在しないことはタイマーの一秒待ちで判定しています。

package main

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

//
// to use channel instead of "WaitGroup"
//
// in this case, slower than WaitGroup. Channel may be useful when it takes long processing time and less inforamtion size
//
func main() {
	maxNumber := 1000*10000
	var mu sync.Mutex
	ch := make(chan int)
	defer close(ch)
	c := 2
	oddCh := []int{}
	tStart := time.Now()
	tStop := time.Now()
	for i := 2; i <= maxNumber; i++ {
		go func() {
			flag := true		// if odd number, stay "true"
			mu.Lock()
			defer mu.Unlock()
			for j :=2; j*j <= c ; j++ {
				if c%j == 0{
					flag = false
					break
				}
			}
			if flag == true{
				ch <- c
			}			
			c++
		}()
	}
	for i:= 0; i < maxNumber; i++{				// set odd numbers to the slice
		setBreak := false
		select {
		case p := <- ch:
			oddCh = append(oddCh, p)
			tStop = time.Now()
		case <- time.After(time.Second):		// to check last "ch" data
			fmt.Println("Time Out!")
			setBreak = true
		}
		if setBreak == true{
			break
		}
	}
	
	fmt.Println("len : ", len(oddCh))

	el := tStop.Sub(tStart)
	fmt.Println(el)
}

実はWaitGroupを使った場合に比較して、処理時間は5倍ぐらいになっています。おそらく渡しているのが素数というint形式データを渡しているだけでオーバーヘッドが大きい。したがってchannelを使うのに細かなデータをやり取りするには向かないんだろうと思います。

いずれにしろこのような簡単な処理では、goroutineも使わずにgoの実行環境でマルチコアを使う方が一番高速なのだから、余計なことをやらないのがいちばんのようです。

 

admin