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言語(Golang)におけるバッファ付channelについて

Last updated at Posted at 2024-10-19
package main

import (
	"fmt"
	"math/rand"
	"time"
)

func processChannel(ch  chan int) []int { 
	const maxConc = 10
	results := make(chan int, maxConc)
	for i := 0; i < maxConc; i++ {
		go func() {
			v := <- ch
			results <- process(v)
		}()
	}
	fmt.Println("ゴルーチン 起動完了")
	
	var out []int // intのスライス
	for i:=0; i<maxConc; i++ {
		out = append(out, <-results) // 結果を受け取って後ろに追加
	}
	return out
}

func process(v int) int {	
	returnVal := v*v
	rand.Seed(time.Now().UnixNano()) // シードの指定
	sleepSec := rand.Intn(3) // 0以上3未満の整数を戻す

	fmt.Println("process:", v, returnVal, sleepSec)
	time.Sleep(time.Duration(sleepSec)*time.Second)
	return returnVal
}


func main() {
	ch := make(chan int)

	var result []int;

	go func() {  // 処理してもらう数値をchに入れる
		for i := 0; i < 100; i++ {
			ch <- i
		}
	}()
	
	result = processChannel(ch)
	
	fmt.Printf("result: %d\n", result)
}
func processChannel(ch  chan int) []int { 

processChannelという関数を定義しています。この関数は、整数型のチャネルchを受け取り、整数のスライスを返します。

	const maxConc = 10

maxConcという定数を定義し、同時に起動するゴルーチンの数を10に設定しています。

	results := make(chan int, maxConc)

resultsというチャネルを作成しています。このチャネルは、整数を受け取るためのもので、バッファサイズはmaxConc(10)です。

	for i := 0; i < maxConc; i++ {
		go func() {

maxConcの数だけループを回し、各ループで新しいゴルーチンを開始します。

			v := <- ch

チャネルchから整数を受け取り、それを変数vに格納します。

			results <- process(v)

受け取った整数vprocess関数に渡し、その結果をresultsチャネルに送信します。

		}()
	}

ここで、ゴルーチンの定義が終了します。これにより、各ループのたびに独立した処理が行われます。

	fmt.Println("ゴルーチン 起動完了")

すべてのゴルーチンが起動したことを示すメッセージを出力します。

	var out []int // intのスライス

整数のスライスoutを初期化します。結果を格納するために使用します。

	for i:=0; i<maxConc; i++ {
		out = append(out, <-results) // 結果を受け取って後ろに追加
	}

maxConc回ループを回し、resultsチャネルから結果を受け取ってoutスライスに追加します。

	return out
}

最終的な結果のスライスoutを返します。

func process(v int) int {	

processという関数を定義しています。この関数は整数vを受け取り、整数を返します。

	returnVal := v*v

引数vの二乗を計算し、returnValに格納します。

	rand.Seed(time.Now().UnixNano()) // シードの指定

乱数生成器にシードを設定します。これにより、毎回異なる乱数を生成することができます。

	sleepSec := rand.Intn(3) // 0以上3未満の整数を戻す

0以上3未満のランダムな整数を生成し、sleepSecに格納します。

	fmt.Println("process:", v, returnVal, sleepSec)

process関数の入力値、計算結果、スリープ秒数を出力します。

	time.Sleep(time.Duration(sleepSec)*time.Second)

生成した乱数の秒数だけスリープします。これにより、処理がランダムに遅延します。

	return returnVal
}

計算結果returnValを返します。

	ch := make(chan int)

整数型のチャネルchを作成します。これにより、整数をゴルーチンに送信できます。

	var result []int;

結果を格納するための整数スライスresultを宣言します。

	go func() {  // 処理してもらう数値をchに入れる

ゴルーチンを起動し、内部で処理する整数をチャネルに送信します。

		for i := 0; i < 100; i++ {
			ch <- i
		}

0から99までの整数をchチャネルに送信します。

	}()

ゴルーチンの定義が終了します。

	result = processChannel(ch)

processChannel関数を呼び出し、チャネルchからの結果をresultに格納します。

	fmt.Printf("result: %d\n", result)

このコードにおけるバッファ付きチャネルの使用について詳しく解説します。

バッファ付きチャネルとは

Go言語におけるチャネルは、ゴルーチン間でデータを送受信するための構造です。チャネルには「バッファ付き」と「バッファなし」の2種類があります。

  • バッファなしのチャネル: 送信と受信が同期的に行われます。つまり、送信側がデータを送ると、受信側がそれを受け取るまで次の処理に進むことができません。
  • バッファ付きのチャネル: あらかじめ指定したサイズのバッファを持ち、送信側は受信側が受け取る前に一定数のデータを送信できます。これにより、送信側と受信側の処理が非同期に行われることが可能となります。

バッファ付きチャネル

results := make(chan int, maxConc)

1. バッファサイズの指定

maxConc(10)をバッファサイズとして指定しています。これにより、最大で10個の整数をチャネルresultsに送信できるようになります。これは、同時に最大10個のゴルーチンが実行され、それぞれがresultsチャネルに結果を送信することを意味します。

2. 非同期処理の実現

バッファ付きチャネルを使用することで、processChannel関数内のゴルーチンは、他のゴルーチンが結果を受信するのを待たずに、即座にresultsチャネルに結果を送信できます。これにより、各ゴルーチンは独立して動作し、並行処理の利点を最大限に活かすことができます。

3. 結果の収集

processChannel関数内では、次のようにループを使って結果を収集しています。

for i := 0; i < maxConc; i++ {
    out = append(out, <-results)
}

ここでは、resultsチャネルから最大10個の結果を受信し、スライスoutに追加しています。バッファ付きチャネルがあることで、受信側が結果を取得する際に、送信側がすでに結果を送信している状態が保証されます。

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?