- Go言語のコーディングしている最中に、バグを指摘してくる(お前はツンデレ彼女か)
- 適当なメソッドを書き込むと、自動的にimport関数を付け加えてくるところ(お前はお袋か)
- バグではないけど、不効率なコーディングをしていると、もっと良いやり方を提案してくる(お前は構いたがりのメンターか)
―― なんか、ちょっと怖い
江端智一のホームページ
―― なんか、ちょっと怖い
https://teratail.com/questions/370090?nli=619ad631-d4fc-405f-a649-44670a040506#reply-502318
もの凄く助かりました。
nobonoboさんに心からの感謝を
C:\Users\ebata\goga\3-10
/*
いっせいブロードキャストをするのに一般的に使われているのはPubSubと呼ばれる方式です。
サブスクライブを複数あらかじめおこなっておき、パブリッシュでメッセージを送ると
複数のサブスクライブ先に同じメッセージを配信するというものです。
おそらくこの方式は発見済みで、想像するに複数のサブスクライブ先をループで巡って
複数回送信することでブロードキャスト相当を実現するのではなく、もっと真に
ブロードキャストしたいということが質問者さんの意図なのかなと。
そういうものを実現するのに「sync.Cond」という標準ライブラリ機能があります。
これの活用方法は実はちゃんとした実例が見つけにくいです。たいてい前者のやり方で済まして
しまっているのと、sync.Condの挙動は若干わかりづらいです。
すこし解説は端折りますが、以下のように記述することで実現できると思います。
ポイントは
タイミングだけをsync.CondのBroadcastで伝える
複数のタスクには共有メモリを通して渡したいメッセージを伝えます
送る方も受ける方も排他ロックを併用するのがCondの使い方でロック期間であれば
共有メモリをコンフリクトなくアクセスできます
この方法はPubSubにくらべ、共有メモリをすべてのgoroutineタスクに伝播したか
どうかを保証する仕組みがないです
つまり、この方法は「低頻度のイベントを大量のタスクに配信」するか、もしくは
「最新の値さえ受け取れればOK」という用途向けです。
*/
package main
import (
"fmt"
"log"
"sync"
"time"
)
type BroadCaster struct {
cond *sync.Cond
id int64
msg string
}
func (bc *BroadCaster) Send(msg string) {
bc.cond.L.Lock()
defer bc.cond.L.Unlock()
bc.id++
bc.msg = msg
bc.cond.Broadcast()
}
func (bc *BroadCaster) Recv(last int64) (int64, string) {
bc.cond.L.Lock()
defer bc.cond.L.Unlock()
for bc.id == last {
bc.cond.Wait()
}
return bc.id, bc.msg
}
var (
broadcaster = &BroadCaster{
cond: sync.NewCond(&sync.Mutex{}),
}
)
func task(i int) {
log.Println("task:", i, " start")
defer log.Println("task:", i, " stop")
last := int64(0)
for {
id, msg := broadcaster.Recv(last)
last = id
log.Println("task:", i, msg)
}
}
func main() {
for i := 0; i < 3; i++ {
go task(i)
}
for i := 0; i < 3; i++ {
time.Sleep(1 * time.Second)
broadcaster.Send(fmt.Sprintf("hello, world: %d", i))
}
time.Sleep(1 * time.Second)
}
Keyword sync.Cond, sync.Broadcast,
wg.Add(): wg.Add(n)でn個の並行処理が存在することを伝え
wg.Done(): wg.Done()で終了を伝える
wg.Wait():wg.Wait()で並行処理が終わるまで(wg.Done()で終了を伝えるまで)処理をやめない
=======================
https://github.com/SierraSoftworks/multicast
マルチキャストでは、チャンネルをリスナーのリンクリストとして実装しています。リスナーは、受信したメッセージを次のリスナーに自動的に転送してから、自分のCチャンネルで公開します。
このアプローチにより、チャネルに属するリスナーの配列を維持する必要がなくなり、実装が大幅に簡素化されます。
=======================
以下は、readme.mdに記載されているプログラムを、ちょっとだけ改造したもの(syncを加えた)
package main
import (
"fmt"
"sync"
"github.com/SierraSoftworks/multicast"
)
func main() {
c := multicast.New()
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
l := c.Listen()
wg.Done()
defer wg.Done()
for msg := range l.C {
fmt.Printf("Listener 1: %s\n", msg)
}
fmt.Println("Listener 1 Closed")
}()
go func() {
l := c.Listen()
wg.Done()
defer wg.Done()
for msg := range l.C {
fmt.Printf("Listener 2: %s\n", msg)
}
fmt.Println("Listener 2 Closed")
}()
wg.Wait()
wg.Add(2)
c.C <- "1 Hello World!"
c.C <- "2 Hello World!"
c.C <- "3 Hello World!"
c.C <- "4 Hello World!"
c.Close()
wg.Wait()
}
ebata@DESKTOP-P6KREM0 MINGW64 ~/goga/3-7
$ go run main.go
Listener 1: 1 Hello World!
Listener 1: 2 Hello World!
Listener 2: 1 Hello World!
Listener 2: 2 Hello World!
Listener 2: 3 Hello World!
Listener 2: 4 Hello World!
Listener 2 Closed
Listener 1: 3 Hello World!
Listener 1: 4 Hello World!
Listener 1 Closed
久しぶりに、「世界に感謝を」という気持ちになりました。
https://github.com/SierraSoftworks/multicast/blob/main/channel.goの、コメントに日本語コメント(翻訳)を付けたもの
package multicast
import "sync"
// Channel represents a multicast channel container which provides
// a writable channel C and allows multiple listeners to be connected.
// Channelは、書き込み可能なチャンネルCを提供し、複数のリスナーの接続を可能にする
// マルチキャストチャンネルコンテナを表します。
type Channel struct {
// C is a writable channel on which you can send messages which will
// be delivered to all connected listeners.
// Cは書き込み可能なチャンネルで、接続されているすべてのリスナーに配信される
// メッセージを送ることができます。
C chan<- interface{}
c chan interface{}
l *Listener
m sync.Mutex
}
// New creates a new multicast channel container which can have listeners
// connected to it and messages sent via its C channel property.
// このコンテナにはリスナーが接続され、C channelプロパティでメッセージが送信されます。
func New() *Channel {
c := make(chan interface{})
return From(c)
}
// From creates a new multicast channel which exposes messages it receives
// on the provided channel to all connected listeners.
// Fromは、新しいマルチキャストチャネルを作成し、提供されたチャネルで受信した
// メッセージを、接続されているすべてのリスナーに公開します。
func From(c chan interface{}) *Channel {
return &Channel{
C: c,
c: c,
}
}
// Listen returns a new listener instance attached to this channel.
// Each listener will receive a single instance of each message sent
// to the channel.
// Listenは、このチャンネルに接続された新しいリスナーのインスタンスを返します。
//各リスナーは、チャンネルに送信された各メッセージのインスタンスを1つずつ受信します。
func (c *Channel) Listen() *Listener {
c.m.Lock()
defer c.m.Unlock()
if c.l == nil {
c.l = NewListener(c.c)
} else {
c.l = c.l.Chain()
}
return c.l
}
// Close is a convenience function for closing the top level channel.
// You may also close the channel directly by using `close(c.C)`.
// Closeは、トップレベルのチャンネルを閉じるための便利な関数です。
// close(c.C)`を使ってチャンネルを直接閉じることもできます。
func (c *Channel) Close() {
c.m.Lock()
defer c.m.Unlock()
close(c.c)
}
https://github.com/SierraSoftworks/multicast/blob/main/listener.goの、コメントに日本語コメント(翻訳)を付けたもの
package multicast
// Listener represents a listener which will receive messages
// from a channel.
// リスナーは、チャンネルからのメッセージを受信するリスナーを表します。
type Listener struct {
C <-chan interface{}
f chan interface{}
}
// NewListener creates a new listener which will forward messages
// it receives on its f channel before exposing them on its C
// channel.
// NewListenerは、Cチャンネルで公開する前に、fチャンネルで受信したメッセージを
// 転送する新しいリスナーを作成します。
// You will very rarely need to use this method directly in your
// applications, prefer using From instead.
// アプリケーションでこのメソッドを直接使用することはほとんどないと思いますが、
// 代わりにFromを使用してください。
func NewListener(source <-chan interface{}) *Listener {
out := make(chan interface{}, 0)
l := &Listener{
C: out,
}
go func() {
for v := range source {
if l.f != nil {
l.f <- v
}
out <- v
}
if l.f != nil {
close(l.f)
}
close(out)
}()
return l
}
// Chain is a shortcut which updates an existing listener to forward
// to a new listener and then returns the new listener.
// Chainは、既存のリスナーを更新して新しいリスナーに転送し、
// その新しいリスナーを返すショートカットです。
// You will generally not need to make use of this method in your
// applications.
// 一般的には、このメソッドを使用する必要はありません。
func (l *Listener) Chain() *Listener {
f := make(chan interface{})
l.f = f
return NewListener(f)
}
package main
import (
"fmt"
"sync"
"time"
"github.com/SierraSoftworks/multicast"
)
func bus_func(i int, wg *sync.WaitGroup, ch *multicast.Channel) {
l := ch.Listen()
wg.Done()
defer wg.Done()
/*
// これだといいんだけど、多面待ちができない
for msg := range l.C {
fmt.Printf("Listener %d: %s\n", i, msg)
}
*/
for {
select {
case v := <-l.C:
if v == nil {
return
}
fmt.Println(i, v)
}
//time.Sleep(1 * time.Second)
}
//fmt.Printf("Listener %d Closed\n", i)
}
func main() {
c := multicast.New()
wg := sync.WaitGroup{}
/*
wg.Add(2)
go func() {
l := c.Listen()
wg.Done()
defer wg.Done()
for msg := range l.C {
fmt.Printf("Listener 1: %s\n", msg)
}
fmt.Println("Listener 1 Closed")
}()
go func() {
l := c.Listen()
wg.Done()
defer wg.Done()
for msg := range l.C {
fmt.Printf("Listener 2: %s\n", msg)
}
fmt.Println("Listener 2 Closed")
}()
*/
for i := 0; i < 3; i++ {
wg.Add(1)
go bus_func(i, &wg, c)
}
wg.Wait()
wg.Add(2)
c.C <- "1 Hello World!"
time.Sleep(time.Second)
c.C <- "2 Hello World!"
time.Sleep(time.Second)
c.C <- "3 Hello World!"
time.Sleep(time.Second)
c.C <- "4 Hello World!"
c.Close()
wg.Wait()
}
package main
import (
"fmt"
"sync"
"time"
"github.com/SierraSoftworks/multicast"
)
func bus_func(i int, wg *sync.WaitGroup, ch *multicast.Channel) {
l := ch.Listen()
wg.Done()
defer wg.Done()
/*
// これだといいんだけど、多面待ちができない
for msg := range l.C {
fmt.Printf("Listener %d: %s\n", i, msg)
}
*/
tick := time.Tick(time.Millisecond * 10000)
for {
select {
case v := <-l.C:
if v == nil { // c.Close() で goroutineをクローズする
return
}
fmt.Println(i, v)
case t := <-tick:
// ここに送信するものを入れる
fmt.Println("tiched", t)
}
//time.Sleep(1 * time.Second)
}
//fmt.Printf("Listener %d Closed\n", i)
}
func main() {
c := multicast.New()
wg := sync.WaitGroup{}
/*
wg.Add(2)
go func() {
l := c.Listen()
wg.Done()
defer wg.Done()
for msg := range l.C {
fmt.Printf("Listener 1: %s\n", msg)
}
fmt.Println("Listener 1 Closed")
}()
go func() {
l := c.Listen()
wg.Done()
defer wg.Done()
for msg := range l.C {
fmt.Printf("Listener 2: %s\n", msg)
}
fmt.Println("Listener 2 Closed")
}()
*/
for i := 0; i < 5; i++ { // ここの"5"は (Aに飛ぶ)
wg.Add(1)
go bus_func(i, &wg, c)
}
wg.Wait()
wg.Add(5) // (Aから)ここの"5"と一致している必要がある(が理由が分からん)
c.C <- "11111!"
//time.Sleep(time.Second)
c.C <- "22222!"
//time.Sleep(time.Second)
c.C <- "33333!"
//time.Sleep(time.Second)
c.C <- "44444!"
//time.Sleep(3 * time.Second)
c.Close() // これでスレッドを全部止める
wg.Wait()
}
package main import ( "fmt" "time" ) var ch chan int // チャネルを運ぶためのグローバルチャネル func bus_func(i int) { ch = make(chan int) // スレッドの中でチャネルを作っても動かない ch <- 10 fmt.Println("After", ch) time.Sleep(3) } func main() { go bus_func(1) fmt.Println(<-ch) }
スレッドの中で(というかサブルーチンの中で)チャネルは厳しいのかな?
package main
import (
"fmt"
"time"
)
var ch chan int // チャネルを運ぶためのグローバルチャネル
func bus_func(i int) {
ch <- 10
fmt.Println("After", ch)
time.Sleep(3)
}
func main() {
ch = make(chan int) // メインで作った場合は動く
go bus_func(1)
fmt.Println(<-ch)
}
チャネルを定数で確保しない方法ってないかなぁ。
スレッドで、オブジェクトを実体化して、そこで送受信させる。
package main
import (
"fmt"
"sync"
"time"
)
type BUS struct {
number int
}
func bus_func(i int, wg *sync.WaitGroup, ch1 chan int, ch2 chan int) {
defer wg.Done()
t := time.NewTicker(1 * time.Second) // 1秒おきに通知
bus := BUS{}
bus.number = i
pointer_bus := &bus
fmt.Println(pointer_bus)
// 待受
for {
select {
case v := <-ch1: // 受信
if v == -1 { //終了コードの受信
return // スレッドを自滅させる
} else {
fmt.Println(v)
}
case <-t.C: // 送信 (1秒まったら、むりやりこっちにくる)
ch2 <- i + 100
}
}
}
//var c = make([]chan int, 3) // 間違い
// var c []chan int これは実行時にエラーとなる
var c1 [3]chan int // チャネルをグローバル変数で置く方法の、現時点での正解
var c2 [3]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)
c1[i] = make(chan int)
c2[i] = make(chan int)
go bus_func(i, &wg, c1[i], c2[i])
}
// バスエージェントにメッセージを送る
c1[0] <- 50
c1[1] <- 30
c1[2] <- 10
c1[0] <- 50
c1[1] <- 30
c1[2] <- 10
c1[0] <- 50
c1[1] <- 30
c1[2] <- 10
fmt.Println(<-c2[0])
fmt.Println(<-c2[1])
fmt.Println(<-c2[2])
c1[0] <- -1 // スレッド終了コードの送信
c1[1] <- -1 // スレッド終了コードの送信
c1[2] <- -1 // スレッド終了コードの送信
}
これまで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
}
package main
// C:\Users\ebata\goga\3-12
import (
"fmt"
"sync"
"time"
)
type BUS struct {
number int
}
//var l sync.Mutex
//var c1 chan int
func (bus *BUS) bus_func_recv(lr *sync.Mutex, cr *sync.Cond) {
// 受信(ブロードキャスト専用)
fmt.Println("bus.number by recv:", bus.number)
lr.Lock()
defer lr.Unlock()
fmt.Println("before cr.Wait")
for {
cr.Wait() // ロック
fmt.Println("hi ") // ここで受信処理を行う
}
}
func (bus *BUS) bus_func_send(lb *sync.Mutex, ch1 chan int) {
// 送信専用
fmt.Println("bus.number by send:", bus.number)
lb.Lock()
defer lb.Unlock()
ch1 <- bus.number
}
func main() {
//wg := sync.WaitGroup{}
l := sync.Mutex{}
c1 := make(chan int)
l2 := sync.Mutex{}
c2 := sync.NewCond(&l2)
for i := 0; i < 10; i++ {
bus := BUS{i}
go bus.bus_func_send(&l, c1)
go bus.bus_func_recv(&l2, c2)
}
time.Sleep(time.Second)
c2.Broadcast()
for {
select {
case v := <-c1:
fmt.Println(v)
//default:
// fmt.Println("default")
case <-time.After(3 * time.Second):
return
}
}
close(c1)
//wg.Wait()
//time.Sleep(3 * time.Second)
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type PERSON struct {
lon_destination float64
lat_destination float64
lon_arrival float64
lat_arrival float64
bus BUS
}
type BUS struct {
lon_present float64
lat_present float64
// person []PERSON
}
func random(min, max float64) float64 {
rand.Seed(time.Now().UnixNano())
return rand.Float64()*(max-min) + min
}
func person(i int, wg *sync.WaitGroup) {
defer wg.Done()
person := PERSON{}
// 出発座標、到着座標の入力
person.lon_destination = random(139.480, 139.460)
person.lat_destination = random(35.602, 35.586)
person.lon_arrival = random(139.480, 139.460)
person.lat_arrival = random(35.602, 35.586)
fmt.Println(person, i)
}
func bus(i int, wg *sync.WaitGroup) {
defer wg.Done()
bus := BUS{}
fmt.Println(bus, i)
}
func main() {
var wg sync.WaitGroup
defer wg.Wait()
// バスエージェントの生成 3台
for i := 0; i < 3; i++ {
wg.Add(1)
go bus(i, &wg)
}
i := 0
for {
time.Sleep(3 * time.Second)
wg.Add(1)
i++
go person(i, &wg)
}
}
package main
// C:\Users\ebata\goga\3-15
import (
"fmt"
"sync"
"time"
)
// BroadCasterは管制システムのイメージに近い だから移動体のオブジェクトには含めない
type BroadCaster struct {
cond *sync.Cond
id int64
msg string
}
func (bc *BroadCaster) Send(msg string) {
bc.cond.L.Lock()
defer bc.cond.L.Unlock()
bc.id++
bc.msg = msg
bc.cond.Broadcast()
}
func (bc *BroadCaster) Recv(last int64) (int64, string) {
bc.cond.L.Lock()
defer bc.cond.L.Unlock()
for bc.id == last {
bc.cond.Wait()
}
return bc.id, bc.msg
}
// broadcaster_busをグローバルで実体化
var (
broadcaster_bus = &BroadCaster{
cond: sync.NewCond(&sync.Mutex{}),
}
)
// broadcaster_personをグローバルで実体化
var (
broadcaster_person = &BroadCaster{
cond: sync.NewCond(&sync.Mutex{}),
}
)
// 単一通信の構造体
type SingleCaster struct {
ch chan int // 単一通信路
lock sync.Mutex // 単一通信路のロック
}
// バス用単一通信の実体化
var (
sc_bus = &SingleCaster{
lock: sync.Mutex{},
ch: make(chan int),
}
)
// 人間用単一通信の実体化
var (
sc_person = &SingleCaster{
lock: sync.Mutex{},
ch: make(chan int),
}
)
// 人間用単一通信の実体化
type CONTROL struct {
number int // 管制番号
}
func (control *CONTROL) control_start() {
// バスへの一斉送信
for i := 0; i < 2; i++ {
time.Sleep(1 * time.Second)
broadcaster_bus.Send(fmt.Sprintf("hello, bus world %d", i))
}
// 人間への一斉送信
for i := 0; i < 2; i++ {
time.Sleep(1 * time.Second)
broadcaster_person.Send(fmt.Sprintf("hello, person world %d", i))
}
for {
select {
// case v := <-c1:
case v_b := <-sc_bus.ch:
fmt.Println("catched from bus send", v_b)
case v_p := <-sc_person.ch:
fmt.Println("catched from person send", v_p)
//default:
// fmt.Println("default")
case <-time.After(3 * time.Second):
return
}
}
}
type BUS struct {
number int // バス車両番号
}
func (bus *BUS) bus_func_recv() {
last := int64(0)
for {
id, msg := broadcaster_bus.Recv(last)
last = id
fmt.Println("broadcaset recv:", bus.number, msg)
}
}
func (bus *BUS) bus_func_send() {
// 送信専用
fmt.Println("bus.number by send:", bus.number)
sc_bus.lock.Lock()
defer sc_bus.lock.Unlock()
sc_bus.ch <- bus.number
}
type PERSON struct {
number int // 人間番号
live bool // 存在フラグ 存在:true 消滅:false
}
func (person *PERSON) person_func_recv() {
last := int64(0)
for {
if person.live {
return
}
id, msg := broadcaster_person.Recv(last)
last = id
fmt.Println("broadcaset recv:", person.number, msg)
}
}
func (person *PERSON) person_func_send() {
// 送信専用
fmt.Println("person.number by send:", person.number)
for {
sc_person.lock.Lock()
sc_person.ch <- person.number
sc_person.lock.Unlock()
time.Sleep(time.Second)
}
}
func main() {
// バス3台
for i := 0; i < 3; i++ {
bus := BUS{i}
go bus.bus_func_send()
go bus.bus_func_recv()
}
// 人間10人
for i := 0; i < 10; i++ {
person := PERSON{i, true}
go person.person_func_send()
go person.person_func_recv()
}
time.Sleep(time.Second)
control := CONTROL{}
go control.control_start()
//close(c1)
//wg.Wait()
time.Sleep(10 * time.Second)
}
package main
// C:\Users\ebata\goga\3-17
import (
"fmt"
"sync"
"time"
)
// BroadCasterは管制システムのイメージに近い だから移動体のオブジェクトには含めない
type BroadCaster struct {
cond *sync.Cond
id int64
msg string
}
func (bc *BroadCaster) Send(msg string) {
bc.cond.L.Lock()
defer bc.cond.L.Unlock()
bc.id++
bc.msg = msg
bc.cond.Broadcast()
}
func (bc *BroadCaster) Recv(last int64) (int64, string) {
bc.cond.L.Lock()
defer bc.cond.L.Unlock()
for bc.id == last {
bc.cond.Wait()
}
return bc.id, bc.msg
}
// broadcaster_busをグローバルで実体化
var (
broadcaster_bus = &BroadCaster{
cond: sync.NewCond(&sync.Mutex{}),
}
)
// broadcaster_personをグローバルで実体化
var (
broadcaster_person = &BroadCaster{
cond: sync.NewCond(&sync.Mutex{}),
}
)
// 単一通信の構造体
type SingleCaster struct {
ch chan int // 単一通信路
lock sync.Mutex // 単一通信路のロック
}
// バス用単一通信の実体化
var (
sc_bus = &SingleCaster{
lock: sync.Mutex{},
ch: make(chan int),
}
)
// 人間用単一通信の実体化
var (
sc_person = &SingleCaster{
lock: sync.Mutex{},
ch: make(chan int),
}
)
// 人間用単一通信の実体化
type CONTROL struct {
number int // 管制番号
}
func control_init(wg *sync.WaitGroup) {
defer wg.Done()
// バスへの一斉送信
for i := 0; i < 2; i++ {
time.Sleep(1 * time.Second)
broadcaster_bus.Send(fmt.Sprintf("hello, bus world %d", i))
}
// 人間への一斉送信
for i := 0; i < 2; i++ {
time.Sleep(1 * time.Second)
broadcaster_person.Send(fmt.Sprintf("hello, person world %d", i))
}
for {
select {
// case v := <-c1:
case v_b := <-sc_bus.ch:
fmt.Println("catched from bus send", v_b)
case v_p := <-sc_person.ch:
fmt.Println("catched from person send", v_p)
//default:
// fmt.Println("default")
case <-time.After(3 * time.Second):
return
}
}
}
type BUS struct {
number int // バス車両番号
person_list []*PERSON // バスに乗っている人
}
func (bus *BUS) bus_func_recv() {
last := int64(0)
for {
id, msg := broadcaster_bus.Recv(last)
last = id
fmt.Println("broadcaset recv:", bus.number, msg)
}
}
func (bus *BUS) bus_func_send() {
// 送信専用
fmt.Println("bus.number by send:", bus.number)
sc_bus.lock.Lock()
defer sc_bus.lock.Unlock()
sc_bus.ch <- bus.number
}
func (bus *BUS) add_person_list(person *PERSON) {
bus.person_list = append(bus.person_list, person)
}
func (bus *BUS) del_person_list(number int) {
for cnt := range bus.person_list {
if number == bus.person_list[cnt].number {
bus.person_list = append(bus.person_list[:number], bus.person_list[number+1:]...)
return
}
}
}
type PERSON struct {
number int // 人間番号
live bool // 存在フラグ 存在:true 消滅:false
}
func (person *PERSON) person_func_recv() {
last := int64(0)
for {
if person.live {
return
}
id, msg := broadcaster_person.Recv(last)
last = id
fmt.Println("broadcaset recv:", person.number, msg)
}
}
func (person *PERSON) person_func_send() {
// 送信専用
fmt.Println("person.number by send:", person.number)
for {
sc_person.lock.Lock()
sc_person.ch <- person.number
sc_person.lock.Unlock()
time.Sleep(time.Second)
}
}
func bus_init(wg *sync.WaitGroup, i int) {
defer wg.Done()
bus := BUS{number: i}
go bus.bus_func_send()
go bus.bus_func_recv()
}
func person_init(wg *sync.WaitGroup, i int) {
defer wg.Done()
person := PERSON{number: i}
go person.person_func_send()
go person.person_func_recv()
}
func main() {
wg := sync.WaitGroup{}
// バス3台
for i := 0; i < 3; i++ {
wg.Add(1)
go bus_init(&wg, i)
}
// 人間10人
for i := 0; i < 10; i++ {
wg.Add(1)
go person_init(&wg, i)
}
time.Sleep(time.Second)
// 管制センタ 1つ
wg.Add(1)
go control_init(&wg)
//close(c1)
//wg.Wait() //本来はこれだが、強制終了の為に
time.Sleep(10 * time.Second)
}
うーん、もっとスマートな方法はないかなぁ
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Start!")
// boolの型でchannelを作成する
ch1 := make(chan bool)
ch2 := make(chan bool)
ch3 := make(chan bool)
// goroutineを生成して、サブスレッドで処理する
go func() {
time.Sleep(2 * time.Second)
// chに対してtrueを投げる(送信)
ch1 <- true
ch2 <- true
ch3 <- true
}()
go func() {
fmt.Println("func2 start")
<-ch1
fmt.Println("func2 end")
}()
go func() {
fmt.Println("func3 start")
<-ch2
fmt.Println("func3 end")
}()
//isFin := <-ch // <-chだけでもブロック出来る
fmt.Println("before time.Sleep(10 * time.Second)")
time.Sleep(10 * time.Second)
fmt.Println("after time.Sleep(10 * time.Second)")
<-ch3
// chをクローズする
close(ch1)
close(ch2)
close(ch3)
// 受信した値をprintする
//fmt.Println(isFin)
fmt.Println("Finish!")
}
国土交通省のPLATEAUのサンプルデータを試していますが、3Dデータの高さ方向が出せずにスタックしています。
できるだけ、勉強しないで、てっとり早く成果を出したいだけなんだけどなぁ。
上記の設定にしてみたら、なんかバベルの棟だったか塔だったか、みたいなものが出てきた。
なんか、色々弄っていましたが、
としたら、
のようなものがでてきたけど、多分、これは正解ではないので、また明日以降に挑戦しよう。
あ、ちなみに、QGISのバージョン上げました。