Go言語(Golang)におけるバッファ付channelについて


```go
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)
}
```


```go
func processChannel(ch  chan int) []int { 
```
`processChannel`という関数を定義しています。この関数は、整数型のチャネル`ch`を受け取り、整数のスライスを返します。

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

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

```go
	for i := 0; i < maxConc; i++ {
		go func() {
```
`maxConc`の数だけループを回し、各ループで新しいゴルーチンを開始します。

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

```go
			results <- process(v)
```
受け取った整数`v`を`process`関数に渡し、その結果を`results`チャネルに送信します。

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

```go
	fmt.Println("ゴルーチン 起動完了")
```
すべてのゴルーチンが起動したことを示すメッセージを出力します。

```go
	var out []int // intのスライス
```
整数のスライス`out`を初期化します。結果を格納するために使用します。

```go
	for i:=0; i<maxConc; i++ {
		out = append(out, <-results) // 結果を受け取って後ろに追加
	}
```
`maxConc`回ループを回し、`results`チャネルから結果を受け取って`out`スライスに追加します。

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

```go
func process(v int) int {	
```
`process`という関数を定義しています。この関数は整数`v`を受け取り、整数を返します。

```go
	returnVal := v*v
```
引数`v`の二乗を計算し、`returnVal`に格納します。

```go
	rand.Seed(time.Now().UnixNano()) // シードの指定
```
乱数生成器にシードを設定します。これにより、毎回異なる乱数を生成することができます。

```go
	sleepSec := rand.Intn(3) // 0以上3未満の整数を戻す
```
0以上3未満のランダムな整数を生成し、`sleepSec`に格納します。

```go
	fmt.Println("process:", v, returnVal, sleepSec)
```
`process`関数の入力値、計算結果、スリープ秒数を出力します。

```go
	time.Sleep(time.Duration(sleepSec)*time.Second)
```
生成した乱数の秒数だけスリープします。これにより、処理がランダムに遅延します。

```go
	return returnVal
}
```
計算結果`returnVal`を返します。



```go
	ch := make(chan int)
```
整数型のチャネル`ch`を作成します。これにより、整数をゴルーチンに送信できます。

```go
	var result []int;
```
結果を格納するための整数スライス`result`を宣言します。

```go
	go func() {  // 処理してもらう数値をchに入れる
```
ゴルーチンを起動し、内部で処理する整数をチャネルに送信します。

```go
		for i := 0; i < 100; i++ {
			ch <- i
		}
```
0から99までの整数を`ch`チャネルに送信します。

```go
	}()
```
ゴルーチンの定義が終了します。

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

```go
	fmt.Printf("result: %d\n", result)
```
このコードにおけるバッファ付きチャネルの使用について詳しく解説します。

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

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

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

### バッファ付きチャネル


```go
results := make(chan int, maxConc)
```

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

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

#### 2. 非同期処理の実現

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

#### 3. 結果の収集

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

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

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