Edited at

Goroutine エクササイズ

More than 1 year has passed since last update.

先輩からお題が出されたので、忘れないように記載しておく


お題

Sleep関数を2秒以内に50回実施して、停止した最大、最小、平均ミリ秒数を表示してください

package main

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

func Sleep(i chan int) {
r := rand.Intn(500) + 100 // 止まるミリ秒数の定義.ランダム数
time.Sleep(time.Duration(r) * time.Millisecond) // 止まるミリ秒数の定義
fmt.Printf("I Slept %d millseconds. \n", r)
i <- r
}

func main() {
rand.Seed(time.Now().UnixNano())
// Sleep関数を2秒以内に50回実施して、停止した最大、最小、平均ミリ秒数を表示してください
}


自分の回答

package main

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

func Sleep(i chan int) {
r := rand.Intn(500) + 100 // 止まるミリ秒数の定義.ランダム数
time.Sleep(time.Duration(r) * time.Millisecond) // 止まるミリ秒数の定義
fmt.Printf("I Slept %d millseconds. \n", r)
i <- r
}

func max(a []int) int {
max := a[0]
for _, i := range a {
if i > max {
max = i
}
}
return max
}

func min(a []int) int {
min := a[0]
for _, i := range a {
if i < min {
min = i
}
}
return min
}

func avg(a []int) int {
len := len(a)
sum := 0
for _, i := range a {
sum += i
}
return sum / len
}

func main() {
rand.Seed(time.Now().UnixNano())
// Sleep関数を2秒以内に50回実施して、停止した最大、最小、平均ミリ秒数を表示してください

// チャネルを用意
ch := make(chan int)
finished := make(chan int)

// Sleep関数を50回、並列処理で実行
wg := &sync.WaitGroup{}
for i := 0 ; i < 50 ; i++ {
wg.Add(1)
go func() {
Sleep(ch)
wg.Done()
}()
}

// 全ての並行処理が完了するのを待つ、完了次第、本スレッドに通知
go func(){
wg.Wait()
finished <- 1
}()

// 本スレッドで、並列で実行した結果を受け取る
results := []int{}
LOOP:
for {
select {
case v := <- ch:
results = append(results, v)
case <- finished:
break LOOP
}
}

// 結果の集計
fmt.Println("件数:" + strconv.Itoa(len(results)))
fmt.Println("最大:" + strconv.Itoa(max(results)))
fmt.Println("最小:" + strconv.Itoa(min(results)))
fmt.Println("平均:" + strconv.Itoa(avg(results)))
}


実行結果

件数:50

最大:573
最小:108
平均:311

「ここはこうした方が良い」など、ありましたらコメントいただければ幸いです。


別の方法も考えてみた

チャネルに結果を溜め込んで、完了後に取り出して集計する、今回のはこれで十分っぽい。

package main

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

func Sleep(i chan int) {
r := rand.Intn(500) + 100 // 止まるミリ秒数の定義.ランダム数
time.Sleep(time.Duration(r) * time.Millisecond) // 止まるミリ秒数の定義
fmt.Printf("I Slept %d millseconds. \n", r)
i <- r
}

func max(a []int) int {
max := a[0]
for _, i := range a {
if i > max {
max = i
}
}
return max
}

func min(a []int) int {
min := a[0]
for _, i := range a {
if i < min {
min = i
}
}
return min
}

func avg(a []int) int {
l := len(a)
sum := 0
for _, i := range a {
sum += i
}
return sum / l
}

func main() {
rand.Seed(time.Now().UnixNano())
// Sleep関数を2秒以内に50回実施して、停止した最大、最小、平均ミリ秒数を表示してください

// チャネルを用意
ch := make(chan int, 50)

// Sleep関数を50回、並列処理で実行
wg := &sync.WaitGroup{}
for i := 0 ; i < 50 ; i++ {
wg.Add(1)
go func() {
Sleep(ch)
wg.Done()
}()
}

// 全ての並行処理が完了するのを待つ
wg.Wait()
close(ch)

// 並列で実行した結果を受け取る
results := []int{}
for v := range ch {
results = append(results, v)
}

// 結果の集計
fmt.Println("件数:" + strconv.Itoa(len(results)))
fmt.Println("最大:" + strconv.Itoa(max(results)))
fmt.Println("最小:" + strconv.Itoa(min(results)))
fmt.Println("平均:" + strconv.Itoa(avg(results)))
}