これまでC/C++言語で作ってきたスケーラブルなエージェントシミュレーションを、golangで作りかえようとしています。
これまでもメイン関数に縛られずに、スレッドを自由に動き回すシミュレータは作ってきたのですが、C/C++のスレッドは、いかんせんメモリサイズが大きく、万の単位のエージェントには耐えられないという問題があります。
そんな感じで、golangに乗り換えしているのですが、色々文法が面倒くさいです。
例えば、スレッドの中で作った構造体と通信を行う方法として、go func() で返り値(return)が欲しいと思っていたのだけど、考えてみれば、スレッド化したfunc()は、それが終了するまでreturn値を返す訳ないと気がつきました。
だから,
go func_xxxx()
は、
go i:= finc_xxxx()
もダメだし
i := go func_xxxx()
もダメということで ―― では、スレッドの中の情報にどうやってアクセスすればいいかが、分かりません。
とすれば、スレッド側で送受信機能を持たせることになるのかなぁ、と思って、以下のようなコードを書いてみました。
package main
import (
"fmt"
"sync"
)
type BUS struct {
number int
}
func bus_func(i int, wg *sync.WaitGroup, ch chan int) {
defer wg.Done()
bus := BUS{}
bus.number = i
pointer_bus := &bus
fmt.Println(pointer_bus)
for {
select {
case v := <-ch:
fmt.Println(i, v)
}
}
}
func main() {
var wg sync.WaitGroup
defer wg.Wait()
c := make(chan int)
// バスエージェントの生成 3台
for i := 0; i < 3; i++ {
wg.Add(1)
go bus_func(i, &wg, c)
}
// バスエージェントにメッセージを送る
c <- 50
c <- 30
c <- 10
c <- 50
c <- 30
c <- 10
c <- 50
c <- 30
c <- 10
}
ただ、この場合、cチャネルは適当に投げられるので、どのオブジェクトにメッセージに届くか分からないので、もう少し工夫をしてみます。
package main
import (
"fmt"
"sync"
)
type BUS struct {
number int
}
func bus_func(i int, wg *sync.WaitGroup, ch chan int) {
defer wg.Done()
bus := BUS{}
bus.number = i
pointer_bus := &bus
fmt.Println(pointer_bus)
for {
select {
case v := <-ch:
fmt.Println(i, v)
}
}
}
//var c = make([]chan int, 3) // 間違い
var c [3]chan int // チャネルをグローバル変数で置く方法の、現時点での正解
// var c []chan int これは実行時にエラーとなる
func main() {
var wg sync.WaitGroup
defer wg.Wait()
//c := make(chan int)
// バスエージェントの生成 3台
for i := 0; i < 3; i++ {
wg.Add(1)
c[i] = make(chan int)
go bus_func(i, &wg, c[i])
}
// バスエージェントにメッセージを送る
c[0] <- 50
c[1] <- 30
c[2] <- 10
c[0] <- 50
c[1] <- 30
c[2] <- 10
c[0] <- 50
c[1] <- 30
c[2] <- 10
}