wg.Add(): wg.Add(n)でn個の並行処理が存在することを伝え
wg.Done(): wg.Done()で終了を伝える
wg.Wait():wg.Wait()で並行処理が終わるまで(wg.Done()で終了を伝えるまで)処理をやめない
江端智一のホームページ
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
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のバージョン上げました。
これが出題
嫁さんの答え
江端のアルゴリズムによる答え
直感的に、私のアルゴリズムが勝っていると思うんだが・・・。
30人を3台のバスで運行するDARPに拡張したバージョン
多分、そこそこ合っていると思うんだけどなー。DARPは正解が分からない(NP困難)問題だからなー。
以上
func totalDistance(sliceA []int, prt int) (dis float64, sliceB []int, max_Bus_Count []int)
という関数を作ったのはいいが、これの呼び出しが上手くできずに、ここ数日作業が滞っていました。
結果としては、正解は以下の通り
var sliceZ [100][]int // または、sliceZ := [100][]int{}
var totalDis [100]float64 // または、totalDis := [100]float64{}
max_Bus_Count := []int{} // または、var max_Bus_Count []inttotalDis[0], sliceZ[0], max_Bus_Count = totalDistance(sliceZ[0], 1)
であり、よく分からんのが、":="と "{}"のペアだが、多分、初期値を放り込めるようにしているものだろう(ここでは入れていないが)。
C言語で書くとこんな感じかと。
#include <stdio.h>
int main() {
int sliceZ[100][90];
double totalDis[100];
int max_Bus_Count[3];int a = totalDistance(sliceZ[0], 1, totalDis[0], max_Bus_Count);
}int totalDistance(int slizeZ, int *p, double totalDis, int max_Bus_Count) {
return 0;
}
こうやってみると、Goの配列宣言は、配列が動的に記載できる分、分かりにくいと思う。
なんで、C言語の宣言を踏襲してくれなかったかなーと思うのだが、
サイズを指定して宣言するもの。実体的な値。メモリを参照するものではない。
a := [3]int64{1, 2, 3}
故に、
a := [3]int{1, 2, 3}
b := a
とすると、aとbが、別のメモリ領域に展開される
sliceはarrayへの参照を持つデータ構造
s1 := []int{1,2,3} # ここで配列の数(例"3")を宣言しないのがミソ
s2 := s1
s2[1] = 0
こっちは、s1とs2が同じ値になる。
append()で要素数を追加する
先程、突然、自宅から、全てのWebアクセスができなくなりました。自宅PCの再起動なども試みたのですが、復活しません。
ところが、会社のシステムに繋っているセキュアPC(SPC)に関しては、メールの送信ができました。で、SPCから、kobore.netのIPアドレスを入手して、自宅PCのコマンド画面からpingを打ってみました。
応答あり・・・ということは、DNSが動いていないだけだな、と判断して、取り敢えず、自宅PCのDNSを、強制的に、8.8.8.8 (googleが提供しているDNSサーバ(だったと思う))にしました。
よし。これで、このPCだけは使えるようになりました。
だが、我が家全体のネットワークが使えない状況は続いていますので、とりあえず家族に連絡。
さて、ここでホームルータ(Aterm ATERM-BA73A9 )の設定を見にいってみました。
やはりDNSの表示が出なくなっている。「最新状態に更新」を押しても改善なし。
こういう場面での「再起動」は、事態を悪化させることもあるので、(少なくとも8.8.8.8で動いてはいる)勇気がいるのですが、やってみました。
結果として、DNSが表示されるようになって、自宅ネットワークを再開することができました。
家族に連絡して、完了。
もはや、インターネットなしの生活(仕事、娯楽、その他)は考えられませんので、こういう場面に出会うと、私でも凄く怖いです。
以上