2022/03,江端さんの忘備録

2年ぶりに、スキー場に行ってきたのですが ―― 散々な目に合いました。

For the first time in two years, I went to a ski resort -- and I had a bad experience.

「転ける」「板を外す」を最初の1~2本にやるのは仕方がないのですが、コースクローズまでその状態が続きました。

I had no choice but to do the first one or two "falls" and "off the board," but I had to continue to course-close that condition.

なにより、『全長2~3km程度のゲレンデを一気に滑り降りることができなくなった』というのは、ショックでした。

Above all, I was shocked by the fact that "it is no longer possible to ski down slopes of 2 to 3 km in length all at once.

高低差1600メートルのウィスラー・ブラッコム(カナダ)のゲレンデを一気に滑り降り、ヘリコプターを使って山頂からダウンヒルしたこともある、この私が、です。

I have skied down the slopes of Whistler Blackcomb (Canada), with a height difference of 1,600 meters, in one fell swoop, and I have even taken a helicopter downhill from the summit.

それが、エキスパートコースだけでなく、普通の中級コースで、この体たらく。

That is the regular intermediate course as well as the expert course. How miserable I am.

大抵、午後になると、スキーを装着している感じが消えて、一体感の高揚が出てくるのですが、今回は、終日疲労一色で終わりました。

Usually by the afternoon, the feeling of being on skis disappears and a heightened sense of togetherness emerges, but this time, I ended the entire day feeling exhausted.

ゲレンデから引き上げた後、スキーブーツを脱ぐのも、ウェアのボタンを外す体力も消えて、全く体が動かなくなりました。

After pulling off the slopes, my strength to take off my ski boots or unbutton my clothes disappeared, and I could not move at all.

正直、衝撃を受けています。

I am honestly shocked.

-----

スキー場の食事は、改善されているとは言え、それでも値段に見合っている品質とは思えません。

Although the food at the ski resort is improving, I still don't think the quality is worth the price.

ですので、今回は、コンビニで菓子パンを購入して、ゲレンデのロッジで、それをかじっていました。

So this time, I bought some pastries at a convenience store and nibbled on them at the lodge on the slope.

今回は9:30から、16:00まで、2回の休憩を除いて、ずっと滑り続けていたので、オーバーワークだったかもしれませんが、それでも、カロリー計算上は、十分であると見積っていました。

This time, I skied from 9:30 to 16:00, with the exception of two breaks, so I may have been overworked, but I still estimated it to be enough for calorie counting purposes.

-----

これは、私が中学生の頃、お金も持たずに、思いつきで、自転車での全周100kmの半島一周をした時に、全く体が動かなくなった時の症状に似ていました。

This was similar to the symptoms I had when I was in junior high school, when I had no money, and on a whim, did a 100 km round-the-peninsula bicycle ride, and was completely immobilized.

―― ハンガーノック?

"Hunger knock?"

お腹が減っていなくても、空腹を感じないまま運動を続け、極度の低血糖状態に陥り、体を動かすためのエネルギーを使い切ってしまう、という現象です。

Hunger knock is a phenomenon in which a person continues to exercise without feeling hungry, even if he or she is not hungry, resulting in an extremely low blood sugar state and using up all the energy to move the body.

最近の在宅勤務で、食料も飲料水も減ってきています。運動不足は言うまでもありません。

I have been working from home recently and have been running low on food and drinking water. Not to mention the lack of exercise.

2年間、運動をしていないところに、5時間程度のぶっつづけの運動をしたのであれば、ハンガーノックの可能性は十分に考えられます。

If I has not exercised for two years and has been exercising for about five hours straight, a hunger knock is quite possible.

-----

帰りの高速道路では、完全に危険と感じられる睡魔に襲われ、近くのPAに逃げ込みました。

On the highway on the way back, I had a sleeping spell that felt completely dangerous and I had to flee to a nearby PA.

そして、自動車を停めた途端、気を失いました(あれは、「仮眠」というレベルではなかった)。

And as soon as I stopped the automobile, I passed out (that was not the level of "napping").

その後も、食欲はなかったのですが、帰宅の為に、アイスクリーム等の強制摂取を実施しました。

After that, I had no appetite, but I implemented a forced intake of ice cream and other foods for my return home.

-----

総じて、これらの現象を一纏めに説明する言葉があります。

In general, there is a single word that describes all of these phenomena.

『歳を取った』

"I'm getting old"

です。

「歳を取る」のは仕方がないです。

It's inevitable that I "get old."

しかし、体力や持久力の劣化は、自分の稼動域(行動範囲)を狭めることになります。

However, a decline in muscle strength and endurance will reduce one's range of motion (range of action).

私は、死ぬ直前まで『思い立てば、世界中のどこにでもフラっと出掛けることができる体』を維持したいです。

I want to maintain a body that can go anywhere in the world at a moment's notice until just before I die.

-----

ああ、そう言えば、室内懸垂、励んでいます。

部屋に鉄棒を作ってみた

Oh, by the way, I am working hard on indoor pull-ups.

先日、江端式懸垂(*)で、連続4回を達成できました。

The other day, I was able to achieve four consecutive Ebata-style pull-ups(*).

(*)江端の部屋の屋根に設置したバーを使って、天井に頭をぶつけるだけで"1回"とみなす、ズルい懸垂ルール

(*)Using a bar set up on the roof of Ebata's room, a cheater's pull-ups are considered "one time" just by hitting your head against the ceiling.

ちなみに、今日は"1回"もできませんでした。

By the way, I couldn't even do "once" today.

筋肉痛で、階下に降りるのも、大変です。

I have muscle aches all over my body and it is very difficult to get downstairs.

2022/03,江端さんの忘備録

金曜日に「3連休」であることを知り、そして、この日を逃すともう今年度はチャンスがない、と考えました。

On Friday, I knew of the "three-day weekend" and then decided that if I missed it, I would not have another chance this fiscal year.

で、この2日間で、必死にコラム原稿を書き上げて、先程、編集部に提出してきました。

So, over the past two days, I have been frantically writing a column manuscript and have just submitted it to the editorial office.

今(22時)から、睡眠薬をぶっこんで寝ます。

I'm going to bed now (10pm) with a bump of sleeping pills.

"Happy Skiing day of the year!!"

■自宅から、3時間以内で到着できて、

- I can arrive within 3 hours from your home.

■そこそこ過激な斜面(エキスパートコース)があって、

- There are some extreme slopes (expert courses).

■3月でも、比較的雪質の良いところ

- Even in March, the snow quality is relatively good

となると、どうしても「川場スキー場」になってしまいます。

Considering the above conditions, it is inevitably "Kawaba Ski Resort".

思えば、ここ10年間、ここ以外のスキー場に行っていません。

Thinking back, I have not been to any other ski resort but this one for the last 10 years.

私の気が変わらないうちに、先程オンラインでスキー券も購入してしまいました。

Before I could change my mind, I also just purchased a ski pass online.

-----

という訳で、私は、明日、年に一度の完全オフです。

So, I am completely off tomorrow, once a year.

たった一人の「スキー合宿」に行ってきます。

I am going to a "ski camp" of only one person.

未分類

コロナ関係のコラム(第8弾)を執筆しているのですが、どうにも、分かりやすいデータが見つからなくて困っています。

私が知りたいのは、ざっくりとした「ワクチン非接種者:ワクチン接種者」の感染率と死亡率です。

これだけのことなのに、なんでグラフが出てこないんだ? と思いながら、捜していたのですが、

神奈川県の、新型コロナワクチンの有効性-ブレイクスルー感染調査から

が、比較的分かりやすいグラフを使っていましたので、ここを参照しています。

ふむ、感染者の97%以上が、ワクチン接種を選択しなかった人、ということですね。

このグラフを見る限り、死亡者の大半が、ワクチン接種を選択しなかった人、と読めます。

現在の日本では「ワクチン非接種者:ワクチン接種者 = 2:8」だから、それを勘案すると、ワクチン非接種者は、さらにリスクが高いと言えそうです。

以上

 

 

2022/03,江端さんの忘備録

ロシアのウクライナ侵攻前から、私は「テレ東BIZ」をウォッチし続けています。

I have been watching "TV Tokyo BIZ" since before the Russian invasion of Ukraine.

「この番組はいいな」と思っています。

I like this program.

解説者が、丹念に勉強して、調べているように見えるからです。

This is because the commentator appears to have studied and researched the subject with great care.

私、解説者が「専門家」である必要はないと思っています。

I do not believe that commentators need necessarily be "experts".

むしろ、その分野の素人が、最新のニュースソースと定量的な数値(歴史も含む)を用いて、そこから導いた仮説(地味な仮説)の方が、私には役に立ちます。

Rather, I find it more useful to have a hypothesis (a humble hypothesis) derived from it by a person outside the field, using up-to-date news sources and quantitative figures (including history).

-----

専門家、論者、有識者といわれる皆さん ―― 『うるさい』

To all the so-called experts, commentators, and pundits -- "Shut up.

あなたたちの「悲しい」やら「酷い」やら「正義」やら、そんなものを持ち込まないで下さい。

Please don't bring your "sad" or "terrible" or "righteous" or whatever into me.

私は、あなたがたの願望(理念、理想)を混入させたコメントなんぞに、1mmも興味ありません。

I am not interested in a single millimeter of your comments laced with your desires (ideals, ideals).

私がニュース解説に求めているものは、「数字を用いて説明される事項」であり、そして、その事実から導かれる客観的な「見解」です。

What I look for in a news commentary is "matters explained with figures" and an objective "view" derived from those facts.

水が低いところに流れていくように、普通に考えれば、普通に導かれる、普通の予測です。

It is a normal forecast, normally guided by normal thinking, just as water flows to a lower place.

-----

「テレ東BIZ」では、戦争開始前に、

In "TV Tokyo BIZ," before the war began, the following commentary was given

『ウクライナ侵攻は、客観的な情報を纏めると"ない"と考えるのが普通』

"Based on objective information, it is common to assume that there will be no invasion of Ukraine.

『なぜなら、ウクライナ全土を実効支配し続けるのは、兵力や財力の観点から無理があるから』

"Because it is impossible to maintain effective control over the whole of Ukraine in terms of troops and financial resources.

『それでも、歴史上の戦争は、概ね、予想外のことで始まっている。今回も何が起こるか分からない』

"Still, wars throughout history have generally started with the unexpected. We don't know what will happen this time either."

と解説しており、今、まさに、その予測通りのことが起こっています。

Right now, that is exactly what the program predicted would happen.

「テレ東BIZ」で用いた数値は、人員、武装の種類と数、ウクライナ国土の面積と、戦争継続に必要な経費くらいの、ラフなものでしてが、私には非常に肚に落ちました。

The figures used in "TV Tokyo BIZ" were very rough, about the number and type of personnel and armaments, the area of Ukraine, and the expenses required to continue the war, but they were very clear to me.

専門家、論者、有識者といわれる皆さん。

To all of you who are called experts, orators, or intellectuals.

この戦争を語るなら、まず、この程度の数値がスラスラと出てくるくらいは勉強をしてから、論じて下さい。

If you are going to talk about this war, please first study enough to be able to slur these figures before discussing them.

-----

例えば、現在のウクライナの人口は4400万人です。

For example, Ukraine's current population is 44 million.

そして、現在、200万人強が国外への避難をしています。

And just over 2 million people have now fled the country.

つまり、脱出できている人数は、わずか5%弱です。

In other words, only less than 5% of the population is able to escape.

国民の大半は国外に脱出できていません。

he majority of the population has not been able to leave the country.

ポーランドの人口は4000万人、ルーマニアの人口は2000万人、スロバキアの人口は500万人、モルドバなんて、300万人弱です。

Poland has a population of 40 million, Romania 20 million, Slovakia 5 million, and Moldova less than 3 million.

ここに、ウクライナの人口の半分、2000万人が逃げこむことができるか? ―― できるわけがない。

Can 20 million people, half of Ukraine's population, flee here? -- It can't be done.

そして、国内に残っている4000万人の反ロシア感情(一部、親ロシア派もいる)で一致する国民を、ロシアは実効支配できるか? ―― かなり難しいだろう。

And can Russia effectively control the 40 million people remaining in the country who are united in their anti-Russian (and some pro-Russian) sentiments? -- It will be very difficult.

出典: 北大西洋条約機構(NATO)について(https://www.mofa.go.jp/mofaj/files/100156880.pdf)

「テレ東BIZ」の解説は、こんな感じです(上記の数値は、私が今、5分間で調べました)。

Here's how "TV Tokyo BIZ" describes it (I just spent 5 minutes looking up the numbers above).

という訳で、ウクライナ侵攻に関するニュースについては、私は、"NHK"と"テレ東BIZ"だけで把握しています。

Therefore, I keep track of the news regarding the invasion of Ukraine only on "NHK" and "TV Tokyo BIZ".

未分類

詳しくは、1-9/readme.md 参照のこと

2022/03,江端さんの忘備録

今回の「ウクライナ侵攻」と、(私から見て)ほぼ同じ理由と同じ条件で行われた侵攻があります。

There is this "invasion of Ukraine" and an invasion that (from my point of view) was carried out for almost the same reasons and under the same conditions.

ソビエト連邦軍主導(今のロシア)のワルシャワ条約機構軍による軍事介入(1968)の「チェコ事件」です。

The "Czech Incident" was a military intervention (1968) by Soviet Union-led (now Russian) Warsaw Pact Organization forces.

「プラハの春」「ブレジネフ・ドクトリン」で覚えている人が多いかもしれません。

You may remember them from "Prague Spring" and "The Brezhnev Doctrine."

(ちなみに、江端は「ドクトリン」という言葉を濫用する傾向がありますが、この(ブレジネフ・ドクトリン)からの引用です)

(Incidentally, Ebata tends to abuse the term "doctrine," but he is quoting from this (Brezhnev Doctrine).

-----

「プラハの春」とは、社会主義国家であるチェコスロバキアが、社会主義体制の中で「人間の顔をした社会主義」というスローガンの元に、

The "Prague Spring" was the following activities of Czechoslovakia, a socialist state, under the slogan "socialism with a human face" within the socialist system.

(1)共産党へ一党支配からの脱却

(1) Breaking away from one-party rule to the Communist Party

(2)企業責任の拡大や市場機能の導入など、資本主義の経済改革

(2) Economic reforms of capitalism, such as the expansion of corporate responsibility and the introduction of market functions

(3)言論や芸術活動の自由化

(3) Liberalization of speech and artistic activities

(4)科学技術の導入を通した西側との経済関係の強化

(4) Strengthen economic ties with the West through the introduction of science and technology

を掲げた運動を言い、

「チェコ事件」とは、ワルシャワ条約機構軍(実質的にはソ連軍)が、この活動(プラハの春)を武力弾圧して、現政権を倒して、ソ連よりの(傀儡)政権を打ち立てた事件です。

The "Czech Incident" was an incident in which Warsaw Pact forces (in effect, Soviet forces) suppressed this activity by force, toppling the current government and establishing a more Soviet (puppet) government.

-----

私、この「チェコ事件」の軍事介入から武力制圧までの時間を調べてみたのですが、

I, looked up the time between the military intervention and the armed suppression of this "Czech Incident"

―― たったの2日間

It was "Only two days"

でした。

この時、市民は抗戦しません(できません)でしたし、西側も「ブレジネフ・ドクトリン」を、事実上、黙認しました。

At this time, the public did not fight back, and the West effectively tacitly endorsed the "Brezhnev Doctrine.

-----

で、まあ、そういうことを知っている私は ―― 正直に言いますが、

And, well, I know that kind of thing -- I'm going to be honest with you.

『今回のウクライナ侵攻は、4日間で、ロシアの制圧で終了する』と思っていました。

I thought, 'This invasion of Ukraine will end in four days, with Russia in control'

加えて、『その後、ロシアは、ウクライナ国内のゲリラ活動に、散々苦しめられた後、20年後に撤収することになる』という、アフガニスタン侵攻のパターンを想定していました(これは、米国のベトナム戦争とも同じ)

In addition, the pattern of the invasion of Afghanistan was assumed: "After that, Russia will be forced to withdraw after 20 years, after being tormented by guerrilla activities in Ukraine" (this is the same as the US Vietnam War).

だから、今、本当にビックリしています。

So now I am really surprised.

―― 20世紀から現在に至るまでの、列強支配のパラダイムやメソッドは、もはや当てはまらなくなっているのかも

"The paradigms and methods of power domination from the 20th century to the present may no longer apply"

と、実感しています。

I realize that.

-----

で、ウクライナ支援ですが、私の調べた感じでは、こちらは、詐欺サイトなどではないようです。

So, Ukraine Support, from what I have been able to find out, this is not a scam site or anything like that.

日本語のページもあります。

There is also a page in Japanese.

私は、上記のサイトからの各種の支援を考えています。

I am considering various types of assistance from the above mentioned sites.

ここから、ボランティアの登録もできます。

You can also register as a volunteer here.

"IT Product Management"でエントリー登録しても、『ロシアへのサイバー攻撃に参加してくれ』と言われることはないだろうとは、思っていますけど。

"I don't think if I register for an entry in IT Product Management, I will be asked to 'participate in a cyber attack on Russia'.

国内法で裁かれるかどうかは、条文読んでみないと分かりません。

I am not sure whether I will be tried under domestic laws.

2022/03,江端さんの技術メモ

Sync.Cond、broadcastを使うには、条件があるようです

の、最後に記載した、

そういえば、ブロードキャストの送信者が1であった場合は問題がなかったけど、今回は、送信者が3になったところから、変な動きをしだしたことから鑑みて、

送信者、受信者は1:Nの関係でないとだめ

なのかもしれないです。

として、別方式を考えているのですが、「Goの複数のgoroutineに対する、一斉ブロードキャスト」の便利さが、どうにも諦めきれなくて、まだ調べています。

そこで、簡易プログラムで以下の検証を行いました。

目的は以下の通り。

・送信者(sender)(ただし1人)や、受信者(receiver)がランダムなタイミングで出現・消滅しても、ちゃんと動くか

を検証してみました。

// go run main3.go
/*
	boardcast sync.bc 実験
	(1) 送信側(sender)をgoroutineにて大丈夫か
	(2) 受信側(sender)のgoroutineを、送信側の前後で、
	適当なタイミングで生成して、消滅させても大丈夫か
*/

package main

import (
	"fmt"
	"log"
	"math/rand"
	"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 receiver(i int) {

	delete_count := 5 + rand.Intn(10) // ループ回数は5~14回のどれか

	log.Println("recv:", i, " start")
	defer log.Println("recv:", i, " stop")

	last := int64(0)
	for k := 0; k < delete_count; k++ {
		id, msg := broadcaster.Recv(last)
		last = id
		log.Println("recv:", i, msg)
	}

}

func sender() {
	for i := 0; i < 20; i++ { // 20回程度送ってみる
		time.Sleep(1 * time.Second)
		broadcaster.Send(fmt.Sprintf("hello, world: %d", i))
	}
}

func main() {
	for i := 0; i < 3; i++ {
		go receiver(i)
	}

	/*
		for i := 0; i < 100; i++ {
			time.Sleep(1 * time.Second)
			broadcaster.Send(fmt.Sprintf("hello, world: %d", i))
		}
	*/

	go sender()

	for i := 4; i < 6; i++ {
		go receiver(i)
		time.Sleep(1 * time.Second)
	}

	time.Sleep(100 * time.Second) // 排他処理を書くのが面倒なので、ここでmainを眠らせておく

}

これで得られた結果です。

c:\Users\ebata\goga\1-7\test>go run main3.go
go run main3.go
go run main3.go
2022/03/18 12:39:02 recv: 0  start
2022/03/18 12:39:02 recv: 2  start
2022/03/18 12:39:02 recv: 4  start
2022/03/18 12:39:02 recv: 1  start
2022/03/18 12:39:03 recv: 1 hello, world: 0
2022/03/18 12:39:03 recv: 4 hello, world: 0
2022/03/18 12:39:03 recv: 2 hello, world: 0
2022/03/18 12:39:03 recv: 0 hello, world: 0
2022/03/18 12:39:03 recv: 5  start
2022/03/18 12:39:03 recv: 5 hello, world: 0
2022/03/18 12:39:04 recv: 4 hello, world: 1
2022/03/18 12:39:04 recv: 5 hello, world: 1
2022/03/18 12:39:04 recv: 2 hello, world: 1
2022/03/18 12:39:04 recv: 0 hello, world: 1
2022/03/18 12:39:04 recv: 1 hello, world: 1
2022/03/18 12:39:05 recv: 5 hello, world: 2
2022/03/18 12:39:05 recv: 1 hello, world: 2
2022/03/18 12:39:05 recv: 4 hello, world: 2
2022/03/18 12:39:05 recv: 2 hello, world: 2
2022/03/18 12:39:05 recv: 0 hello, world: 2
2022/03/18 12:39:06 recv: 1 hello, world: 3
2022/03/18 12:39:06 recv: 5 hello, world: 3
2022/03/18 12:39:06 recv: 4 hello, world: 3
2022/03/18 12:39:06 recv: 2 hello, world: 3
2022/03/18 12:39:06 recv: 0 hello, world: 3
2022/03/18 12:39:07 recv: 0 hello, world: 4
2022/03/18 12:39:07 recv: 4 hello, world: 4
2022/03/18 12:39:07 recv: 2 hello, world: 4
2022/03/18 12:39:07 recv: 5 hello, world: 4
2022/03/18 12:39:07 recv: 1 hello, world: 4
2022/03/18 12:39:08 recv: 1 hello, world: 5
2022/03/18 12:39:08 recv: 4 hello, world: 5
2022/03/18 12:39:08 recv: 0 hello, world: 5
2022/03/18 12:39:08 recv: 5 hello, world: 5
2022/03/18 12:39:08 recv: 0  stop
2022/03/18 12:39:08 recv: 5  stop
2022/03/18 12:39:08 recv: 2 hello, world: 5
2022/03/18 12:39:09 recv: 2 hello, world: 6
2022/03/18 12:39:09 recv: 1 hello, world: 6
2022/03/18 12:39:09 recv: 4 hello, world: 6
2022/03/18 12:39:10 recv: 4 hello, world: 7
2022/03/18 12:39:10 recv: 2 hello, world: 7
2022/03/18 12:39:10 recv: 1 hello, world: 7
2022/03/18 12:39:11 recv: 1 hello, world: 8
2022/03/18 12:39:11 recv: 4 hello, world: 8
2022/03/18 12:39:11 recv: 2 hello, world: 8
2022/03/18 12:39:12 recv: 2 hello, world: 9
2022/03/18 12:39:12 recv: 4 hello, world: 9
2022/03/18 12:39:12 recv: 1 hello, world: 9
2022/03/18 12:39:13 recv: 1 hello, world: 10
2022/03/18 12:39:13 recv: 2 hello, world: 10
2022/03/18 12:39:13 recv: 4 hello, world: 10
2022/03/18 12:39:14 recv: 4 hello, world: 11
2022/03/18 12:39:14 recv: 1 hello, world: 11
2022/03/18 12:39:14 recv: 1  stop
2022/03/18 12:39:14 recv: 2 hello, world: 11
2022/03/18 12:39:14 recv: 4  stop
2022/03/18 12:39:15 recv: 2 hello, world: 12
2022/03/18 12:39:16 recv: 2 hello, world: 13
2022/03/18 12:39:16 recv: 2  stop

結論としては、

・recvierは、データを重複することなく、またロストすることなく、1つづつキレイに受けとっていた

ということになります。


さて、ここで、今度は、送信者を2人にしてみます。送信者の名前が見易いように、"111"と"999"の番号を付けてます(冗長ですが、プログラムリスト全部を掲載します(私の為に))

// go run main3.go
/*
	boardcast sync.bc 実験
	(1) 送信側(sender)のgoroutineを2つにしたらどうなるか
*/

package main

import (
	"fmt"
	"log"
	"math/rand"
	"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 receiver(i int) {

	delete_count := 5 + rand.Intn(10) // ループ回数は5~14回のどれか

	log.Println("recv:", i, " start")
	defer log.Println("recv:", i, " stop")

	last := int64(0)
	for k := 0; k < delete_count; k++ {
		id, msg := broadcaster.Recv(last)
		last = id
		log.Println("recv:", i, msg)
	}

}

func sender(i int) {
	for k := 0; k < 20; k++ { // 20回程度送ってみる
		time.Sleep(1 * time.Second)
		broadcaster.Send(fmt.Sprintf("hello, world: %d from %d", k, i))
	}
}

func main() {
	for i := 0; i < 3; i++ {
		go receiver(i)
	}

	/*
		for i := 0; i < 100; i++ {
			time.Sleep(1 * time.Second)
			broadcaster.Send(fmt.Sprintf("hello, world: %d", i))
		}
	*/

	go sender(111) // ここに注意
	go sender(999) // ここに注意

	for i := 4; i < 6; i++ {
		go receiver(i)
		time.Sleep(1 * time.Second)
	}

	time.Sleep(100 * time.Second) // 排他処理を書くのが面倒なので、ここでmainを眠らせておく

}

結果は以下の通りになりました。

2022/03/18 12:56:45 recv: 4  start
2022/03/18 12:56:45 recv: 1  start
2022/03/18 12:56:45 recv: 0  start
2022/03/18 12:56:45 recv: 2  start
2022/03/18 12:56:46 recv: 2 hello, world: 0 from 999
2022/03/18 12:56:46 recv: 2 hello, world: 0 from 111
2022/03/18 12:56:46 recv: 5  start
2022/03/18 12:56:46 recv: 5 hello, world: 0 from 111
2022/03/18 12:56:46 recv: 0 hello, world: 0 from 111
2022/03/18 12:56:46 recv: 4 hello, world: 0 from 111
2022/03/18 12:56:46 recv: 1 hello, world: 0 from 111
2022/03/18 12:56:47 recv: 1 hello, world: 1 from 111
2022/03/18 12:56:47 recv: 4 hello, world: 1 from 999
2022/03/18 12:56:47 recv: 1 hello, world: 1 from 999
2022/03/18 12:56:47 recv: 2 hello, world: 1 from 999
2022/03/18 12:56:47 recv: 0 hello, world: 1 from 999
2022/03/18 12:56:47 recv: 5 hello, world: 1 from 111
2022/03/18 12:56:47 recv: 5 hello, world: 1 from 999
2022/03/18 12:56:48 recv: 1 hello, world: 2 from 999
2022/03/18 12:56:48 recv: 5 hello, world: 2 from 999
2022/03/18 12:56:48 recv: 2 hello, world: 2 from 999
2022/03/18 12:56:48 recv: 0 hello, world: 2 from 999
2022/03/18 12:56:48 recv: 4 hello, world: 2 from 999
2022/03/18 12:56:49 recv: 4 hello, world: 3 from 999
2022/03/18 12:56:49 recv: 1 hello, world: 3 from 999
2022/03/18 12:56:49 recv: 5 hello, world: 3 from 999
2022/03/18 12:56:49 recv: 2 hello, world: 3 from 999
2022/03/18 12:56:49 recv: 0 hello, world: 3 from 999
2022/03/18 12:56:49 recv: 0 hello, world: 3 from 111
2022/03/18 12:56:49 recv: 1 hello, world: 3 from 111
2022/03/18 12:56:49 recv: 4 hello, world: 3 from 111
2022/03/18 12:56:49 recv: 5 hello, world: 3 from 111
2022/03/18 12:56:49 recv: 5  stop
2022/03/18 12:56:49 recv: 2 hello, world: 3 from 111
2022/03/18 12:56:49 recv: 1  stop
2022/03/18 12:56:50 recv: 2 hello, world: 4 from 111
2022/03/18 12:56:50 recv: 2 hello, world: 4 from 999
2022/03/18 12:56:50 recv: 0 hello, world: 4 from 111
2022/03/18 12:56:50 recv: 0 hello, world: 4 from 999
2022/03/18 12:56:50 recv: 4 hello, world: 4 from 999
2022/03/18 12:56:51 recv: 4 hello, world: 5 from 999
2022/03/18 12:56:51 recv: 4 hello, world: 5 from 111
2022/03/18 12:56:51 recv: 2 hello, world: 5 from 111
2022/03/18 12:56:51 recv: 0 hello, world: 5 from 111
2022/03/18 12:56:52 recv: 0 hello, world: 6 from 999
2022/03/18 12:56:52 recv: 0 hello, world: 6 from 111
2022/03/18 12:56:52 recv: 4 hello, world: 6 from 111
2022/03/18 12:56:52 recv: 2 hello, world: 6 from 111
2022/03/18 12:56:53 recv: 2 hello, world: 7 from 111
2022/03/18 12:56:53 recv: 2 hello, world: 7 from 999
2022/03/18 12:56:53 recv: 0 hello, world: 7 from 999
2022/03/18 12:56:53 recv: 4 hello, world: 7 from 999
2022/03/18 12:56:54 recv: 4 hello, world: 8 from 111
2022/03/18 12:56:54 recv: 4 hello, world: 8 from 999
2022/03/18 12:56:54 recv: 4  stop
2022/03/18 12:56:54 recv: 2 hello, world: 8 from 111
2022/03/18 12:56:54 recv: 2 hello, world: 8 from 999
2022/03/18 12:56:54 recv: 2  stop
2022/03/18 12:56:54 recv: 0 hello, world: 8 from 111
2022/03/18 12:56:54 recv: 0  stop

ちょっと見難いので、"recv: 2"を、それぞれ異なる送信者ごとに整理してみます。

c:\Users\ebata\goga\1-7\test>grep "recv: 2" dummy.txt | grep 999
grep "recv: 2" dummy.txt | grep 111
2022/03/18 12:56:46 recv: 2 hello, world: 0 from 111
2022/03/18 12:56:49 recv: 2 hello, world: 3 from 111
2022/03/18 12:56:50 recv: 2 hello, world: 4 from 111
2022/03/18 12:56:51 recv: 2 hello, world: 5 from 111
2022/03/18 12:56:52 recv: 2 hello, world: 6 from 111
2022/03/18 12:56:53 recv: 2 hello, world: 7 from 111
2022/03/18 12:56:54 recv: 2 hello, world: 8 from 111

2番がロストしています。

c:\Users\ebata\goga\1-7\test>grep "recv: 2" dummy.txt | grep 999
grep "recv: 2" dummy.txt | grep 999
2022/03/18 12:56:46 recv: 2 hello, world: 0 from 999
2022/03/18 12:56:47 recv: 2 hello, world: 1 from 999
2022/03/18 12:56:48 recv: 2 hello, world: 2 from 999
2022/03/18 12:56:49 recv: 2 hello, world: 3 from 999
2022/03/18 12:56:50 recv: 2 hello, world: 4 from 999
2022/03/18 12:56:53 recv: 2 hello, world: 7 from 999
2022/03/18 12:56:54 recv: 2 hello, world: 8 from 999

5、6番がロストしています。


送信者を1人にすれば、問題が発生する可能性はなくなる」という仮説は成り立ちそうです。

考えてみれば、このプログラムでは、2つの送信者を区別する方法を入れていないのですから、当然かもしれません。

という訳で、送信者を1人にする方法の実装で、もうちょっとがんばってみたいと思います。

ただ、この方式では、送受信の際にロックをかけているので、受信者の数が膨大になれば、プログラム全体のパフォーマンスが劣化する可能性があります。

リアルタイム系のプログラムには、使わない方が良いかもしれません。

ただ、プログラムの動作状況を簡単に見たいようなケースでは、とても便利なので、当面は手放せないと思います。

以上

 

 

 

 

 

2022/03,江端さんの技術メモ

Go の channel 処理パターン集

func main() {
	ii := 10

	queue := make(chan int, 100)
	defer close(queue)

	for i := 0; i < 5; i++ {
		go worker(i, queue)
	}

	for {
		//k := rand.Intn(1000)

		for i := 0; i < 200; i++ {
			queue <- ii
		}

		time.Sleep(1 * time.Second) // 2秒待つ

		ii++
		go worker(ii, queue)

	}

}

func worker(i int, queue chan int) {
	for j := range queue {
		fmt.Println(i, ",", j)
	}
}

2022/03,江端さんの技術メモ

Goの複数のgoroutineに対して、一斉ブロードキャストを行いたい

を教えて貰って、喜んでいたのですが、私のようなカルトな使い方をしているケースでは、正しくデータ送信ができない場合があるようです。

動的に登場して、自動的に消滅するような複数の(かなりの数の)goroutineに対しては、受信データの値が変な値になるようです。

下記は、データ送信元のオブジェクトが、自分の位置情報を撒き散らしながらbroadcast送信をしています。

下記は、この途中からgoroutineをバラバラに30個くらい作って受信したものの一つです。

なんども調べてみたのですが、やはりバグが原因ではないようです。

本日、バグを発見しました! 構造体に送信元のオブジェクトを指定する変数が入っていなかった為、全部同じブロードキャストとして受信先が受信をしてしまっていました(03/18)。

ここから得られる結論は、Sync.Cond、broadcastを使うには、

・broadcast、sync.cond は、最初からgoroutineができあがっている場合

・少量、低速にデータ配信を行う場合

でないと、安定的に動作させるには厳しいようです。

これは、まあ、間違ってはいませんです。

====  追記 =====

そういえば、ブロードキャストの送信者が1であった場合は問題がなかったけど、今回は、送信者が3になったところから、変な動きをしだしたことから鑑みて、

送信者、受信者は1:Nの関係でないとだめ

なのかもしれないです。

これは確定です。詳しくは以下をご覧下さい↓

Goの複数のgoroutineに対する一斉ブロードキャストを、まだ諦めきれない

以上