概要 †Go言語ではゴルーチン(Goroutine)による並列処理が簡単に出来る。 目次 †
メイン処理は起動したゴルーチンの終了を待たない †メイン処理は起動した各ゴルーチンの終了を待たない。(他言語でスレッド起動した場合と同様) sample_goroutine1.go package main import ( "flag" "fmt" "strconv" "time" ) func main(){ printLog("main START") mainSleepSec := getSleepSec() for i := 1; i <= 5; i++ { go sub(i) // ゴルーチンの生成 } time.Sleep(time.Second * mainSleepSec) printLog("main END") } func getSleepSec() time.Duration { flag.Parse() args := flag.Args() if len(args) > 0 { num, _ := strconv.Atoi(args[0]) return time.Duration(num) } else { return time.Duration(6) } } func sub(no int){ sleep := time.Duration(no) printLog(fmt.Sprintf("sub(%d) START (sleep: %d)", no, sleep)) time.Sleep(time.Second * sleep) printLog(fmt.Sprintf("sub(%d) END", no)) } func printLog(msg string){ t := time.Now() //fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d.%06d %s\n", fmt.Printf("%02d:%02d:%02d.%06d %s\n", //t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond() / 1000, msg) } メイン処理側のスリープを5秒にした場合 $ go run sample_goroutine1.go 6 18:46:26.007975 main START 18:46:26.008156 sub(3) START (sleep: 3) 18:46:26.008169 sub(4) START (sleep: 4) 18:46:26.008187 sub(5) START (sleep: 5) 18:46:26.008195 sub(2) START (sleep: 2) 18:46:26.008252 sub(1) START (sleep: 1) 18:46:27.010345 sub(1) END 18:46:28.011988 sub(2) END 18:46:29.008312 sub(3) END 18:46:30.013348 sub(4) END 18:46:31.012110 sub(5) END 18:46:32.011292 main END メイン処理側のスリープを2秒にした場合 $ go run sample_goroutine1.go 3 18:47:00.325989 main START 18:47:00.326173 sub(4) START (sleep: 4) 18:47:00.326166 sub(3) START (sleep: 3) 18:47:00.326189 sub(5) START (sleep: 5) 18:47:00.326195 sub(2) START (sleep: 2) 18:47:00.326234 sub(1) START (sleep: 1) 18:47:01.330963 sub(1) END 18:47:02.331014 sub(2) END 18:47:03.330935 sub(3) END 18:47:03.330962 main END 上記の結果から分かる通り、メイン処理は実行したゴルーチンの終了を待たない。 ゴルーチンの終了を待ち合わせる †メイン処理側でゴルーチンの終了を待ち合わせるには sync.WaitGroup を利用する。 sample_goroutine2.go package main import ( "fmt" "sync" "time" ) var wait = new(sync.WaitGroup) // 追加 func main(){ printLog("main START") for i := 1; i <= 5; i++ { wait.Add(1) // 追加 go sub(i) } wait.Wait() // 追加 printLog("main END") } func sub(no int){ sleep := time.Duration(no) printLog(fmt.Sprintf("sub(%d) START (sleep: %d)", no, sleep)) time.Sleep(time.Second * sleep) printLog(fmt.Sprintf("sub(%d) END", no)) wait.Done() // 追加 } func printLog(msg string){ t := time.Now() fmt.Printf("%02d:%02d:%02d.%06d %s\n", t.Hour(), t.Minute(), t.Second(), t.Nanosecond() / 1000, msg) } 実行結果 $ go run sample_goroutine2.go 18:52:51.336324 main START 18:52:51.336491 sub(5) START (sleep: 5) 18:52:51.336517 sub(3) START (sleep: 3) 18:52:51.336534 sub(2) START (sleep: 2) 18:52:51.336549 sub(4) START (sleep: 4) 18:52:51.336589 sub(1) START (sleep: 1) 18:52:52.340077 sub(1) END 18:52:53.341676 sub(2) END 18:52:54.337123 sub(3) END 18:52:55.341728 sub(4) END 18:52:56.339499 sub(5) END 18:52:56.339582 main END ゴルーチンと値をやり取りする †チャンネルを使用してゴルーチンと値のやり取りが出来る。 sample_goroutine3.go package main import ( "fmt" "sync" "time" ) var wait = new(sync.WaitGroup) func main(){ printLog("main START") var channels []chan string for i := 1; i <= 5; i++ { // チャンネル生成 ch := make(chan string) channels = append(channels, ch) wait.Add(1) go sub(i, ch) } wait.Wait() for i, ch := range channels { // チャンネルから値を受信 message := <-ch fmt.Printf("message[%d]: %s\n", i, message) } printLog("main END") } func sub(no int, ch chan string){ sleep := time.Duration(no) printLog(fmt.Sprintf("sub(%d) START (sleep: %d)", no, sleep)) time.Sleep(time.Second * sleep) printLog(fmt.Sprintf("sub(%d) END", no)) wait.Done() // チャンネルに値を送信 ch <- fmt.Sprintf("sub(%d) finished!", no) } func printLog(msg string){ t := time.Now() fmt.Printf("%02d:%02d:%02d.%06d %s\n", t.Hour(), t.Minute(), t.Second(), t.Nanosecond() / 1000, msg) } 実行結果 $ go run sample_goroutine3.go 19:29:13.767172 main START 19:29:13.767313 sub(5) START (sleep: 5) 19:29:13.767344 sub(3) START (sleep: 3) 19:29:13.767354 sub(4) START (sleep: 4) 19:29:13.767358 sub(2) START (sleep: 2) 19:29:13.767414 sub(1) START (sleep: 1) 19:29:14.770515 sub(1) END 19:29:15.772479 sub(2) END 19:29:16.768126 sub(3) END 19:29:17.771446 sub(4) END 19:29:18.772457 sub(5) END message[0]: sub(1) finished! message[1]: sub(2) finished! message[2]: sub(3) finished! message[3]: sub(4) finished! message[4]: sub(5) finished! 19:29:18.772529 main END |