時代はマルチコア

マルチコア - Wikipedia


一つのCPUに見せかけて、

複数のCPUが搭載されているのが今のパソコンの主流


せっかくマルチコアなんだし、

プログラミングもマルチコアを活かしたいということで、

Go言語のgoroutine(並行処理)を試してみた。


これで平行処理もばっちりだ。

平行計算 - Wikipedia


と言うわけで、

平行処理の練習と解釈の意味を込めて、ここにメモを残す




本来、プログラミングは書いたコードを上から下に向かって順に実行していくもので、


package main

import "fmt"

func main() {
	var s string
	s = "Hello World!"
	fmt.Println(s)	//Hello World!と実行される
}

・main内のコードを実行します

・文字列を表示するためのライブラリを読み込んでおきます

・文字列を入れるためにメモリーを空けておきます。空けた領域をsと名付けます

・sにHello Worldという文字列を入れます

・sに入れた文字列を表示します


こんな感じで上から下にプログラムを実行していく。

これだと実行するのにコアが一つで十分で勿体ない。


なので平行で処理しましょ。

と言うことになる


例えば、

1から順に偶数であるか奇数であるかを調べる処理を作ってみる。

まずは普通に書くと


package main

import "fmt"

func main() {
	var i int

	//1~10まで順に調べる
	for {
		//10になったらやめる
		if i == 10 {
			break
		}

		//偶数の場合
		if i%2 == 0 {
			fmt.Println("偶数です")
			//奇数の場合
		} else {
			fmt.Println("奇数です")
		}

		i++
	}
}

こんな感じ


これを計算する処理と文字を表示する処理に分けてみる。

この時にchannelという互いの処理を繋ぐ変数を用意しておく必要がある。


計算する処理の方をsenderとし、

結果を受け取り表示するreceiverとしておく




とりあえず、senderとreceiverは置いといて、


先にchannelを用意して、senderとreceiverに突っ込む


func main() {
	//偶数の時はchが結果を受け取り、奇数の時はch2が結果を受け取るchannelを用意する
	ch := make(chan int)
	ch2 := make(chan int)
	
	go sender(ch, ch2)
	receiver(ch, ch2)
}

関数名の前にgoと付けて実行すると、他のスレッドを用意して、平行で処理を開始する。

senderで計算した結果を受け取る処理を次の行で実行する。


ここまで書いた上で、senderとreceiverの処理を書いてみると


package main

import "fmt"

func sender(ch chan int, ch2 chan int) {
	var i int
	for {
		//偶数の場合
		if i%2 == 0 {
			//結果をreceiverに送る
			ch <- i
		//奇数の場合
		} else {
			//結果をreceiverに送る
			ch2 <- i
		}
		i++
	}
}

func receiver(ch chan int, ch2 chan int) {
	//何回実行したか?
	var c int
	for {
		c++

		select {
		//偶数の結果を受け取った時
		case <-ch:
			fmt.Println("偶数です")
		//奇数の結果を受け取った時
		case <-ch2:
			fmt.Println("奇数です")
		}

		//結果を10回受け取ったら終了
		if c == 10 {
			break
		}
	}
}

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

	go sender(ch, ch2)
	receiver(ch, ch2)
}

こんな感じ


senderでは計算してreceiverに結果を送る。

この時にchannelを使うんだけど、

それをch := make(chan int)で用意する。

(ch2も同様に用意)


それらを各関数に入れて、処理を開始する

senderではreceiverに結果を送らなければならないので、

計算結果を ch <- iという形で<-でchに入れる


一方、receiverではchに入っている値を受け取らなければならないので、

<- chと書いて値を受け取る。

(receiverのchはsenderからの値が送信されるまで待機してくれる)


今回はあえて、偶数であればch、奇数であればch2にして、

receiverの方のselect文で

case <- ch: つまり、偶数のchannelを受け取った時に処理、

case <- ch2: 奇数のchannelを受け取った時の処理の様に分けて書いてみた。


このコードを実行してみると、


偶数です
奇数です
偶数です
奇数です
偶数です
奇数です
偶数です
奇数です
偶数です
奇数です

こうなった。


まぁ、まったくgoroutineが活かされてないけど、

とりあえずマルチコアっぽい処理は書けた。