あと最近の発見と絶望は、C.selectが呼び出せないこと。select中のdefaultでnonblocking相当にできるけど、可変数なfdをselectしたい相当をどう書けばいいんだろうか。 #golang
— HiroakiKawai (@kwi) July 28, 2014
reflect.Select
を使います。
package main
import (
"fmt"
"math/rand"
"reflect"
"sync"
"time"
)
func multpleSelect(chans []chan bool) (int, bool, bool) {
// chans の数分 select-case 文を作る
cases := make([]reflect.SelectCase, len(chans))
for i, ch := range chans {
cases[i] = reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(ch),
}
}
// 一括で select
i, v, ok := reflect.Select(cases)
return i, v.Interface().(bool), ok
}
func main() {
rand.Seed(time.Now().UnixNano())
// 100個の chan を作るよ
chans := make([]chan bool, 100)
for i := 0; i < 100; i++ {
chans[i] = make(chan bool)
}
// 非同期で100個の chan を同時に待つ
var wg sync.WaitGroup
go func() {
wg.Add(1)
if ch, v, ok := multpleSelect(chans); ok {
fmt.Printf("I am chan-%v, value is %v\n", ch, v)
}
wg.Done()
}()
// ランダムな chan に true を送る
chans[rand.Int() % len(chans)] <- true
wg.Wait()
}
何度も繰り返して待つ場合は、その都度 SelectCase を作るのがコストになり得るので、予め作ったまま保持しておくのが良いかと思います。