Go language part 5

■ このスレッドは過去ログ倉庫に格納されています
2022/02/27(日) 07:43:20.04ID:uWHjNeVw
Goについて扱うスレッドです。
GoはGoogleによって開発された言語です。

公式
https://golang.org

公式ドキュメント
https://golang.org/doc/

公式外パッケージドキュメント
https://godoc.org

ブラウザ上で試し書き
https://play.golang.org


※前スレ
Go language part 4
https://mevius.5ch.net/test/read.cgi/tech/1605467680/
2022/02/27(日) 07:45:13.76ID:uWHjNeVw
公式
https://golang.org

公式ドキュメント
https://golang.org/doc/

公式外パッケージドキュメント
https://godoc.org

ブラウザ上で試し書き
https://play.golang.org
2022/02/27(日) 07:46:00.05ID:uWHjNeVw
あ、これ2のテンプレじゃないのか
2022/02/27(日) 08:59:11.36ID:PVy06kKY
>>992(前スレ)
読んだ。で、やっぱり奇妙なんだけど、多分オーバーヘッドはないと思うよ。

一般的にはガードページなんて必要なくて、コピーオンライトと同じで、
ページ境界を跨いだ場合はハードウェアで検出出来るから、まず普通はそれを使う。
この場合は自前でのチェックは必要ない(ソフトウェアには必要ない)ので、オーバーヘッドはない。
だからGoの当初の初期スタックサイズが4kだったのは非常に納得出来た。ここまではいい。

これを小さくするならハードウェアのサポート無しになるから当然自前でチェックするしかないが、この場合、
・2kも大きすぎ。自分でやるならRustのように64Bytesからとか、4kに拘らず凄く小さいスタックサイズから可能だし、普通はそうする。
・そもそも必要スタックサイズを予見出来ない。というか出来るならコンパイル時に確定的に割り当てれば済んでる。
であって、Rustの実装は非常に納得出来るのだけど、Goのは若干意味不明なんだよ。
(ただまあ何かしら理由はあると思うけど)

2kとかいう、4kに拘ったサイズになってるんだから、多分何かしらハードウェアのサポートを受けてて、
自前ではスタックサイズのチェックはしてないと思うよ。(つまりオーバーヘッドがない)
可能性があるのは、2kをはみ出る時には4k境界を跨ぐようにして(つまりまずは上側を割り当てる)
はみ出た時に2kずらしていくとかだけど。
ただこの方式の場合、初期アロケーションだけは4kでされてしまうので、957のベンチでは40MB越えないとおかしくて、矛盾してる。
だから正直よく分からないが、
多分オーバーヘッドのない方式で実装してて、だから2kとかいう中途半端な巨大サイズになってるのではないかと思う。
2022/02/27(日) 09:14:34.62ID:PVy06kKY
>>998(前スレ)
分かりやすい説明ありがとう。発想は面白いね。
確かにその方式だと死蔵メモリは最小限に留められ、Goの問題は解決されてるはずだね。

>>986(前スレ)
998の通りだと、外部からのプリエンプションではなく、
コルーチンが処理を(自発的に)返してくるから、その単位での切換だろう。
まあこれでも現実的には問題ない気はする。
2022/02/27(日) 09:39:32.40ID:+yReYAPt
ちなみに前スレ1000と同じく、1桁少ない1000スレッドで同じPCでgoを測ると
$ go version
go version go1.13.8 linux/amd64
$ go build main.go && ./t ./main
real 12.02s
user 0.91s
sys 0.22s
rss 3808k
$
やはり4Mを超えない(rssでいいの?とは思うけど)
2022/02/27(日) 10:24:28.50ID:c+lx/lLr
推奨NGWord
正規表現で「.{50}」を設定
長文を排除できます
2022/02/27(日) 14:25:03.95ID:PVy06kKY
>>992(前スレ)
訂正。他も色々漁って、やっぱりオーバーヘッドはあると思えてきた。
ただし多分0〜4cycle/関数呼び出し程度だね。

主に読んだのは以下とか。
https://github.com/tinygo-org/tinygo/issues/2000
https://dave.cheney.net/2014/06/07/five-things-that-make-go-fast
https://dave.cheney.net/2013/06/02/why-is-a-goroutines-stack-infinite

・当初は8kだったが、もっとでかくしろという要求が多かった
・1kに出来てる実装もあるが、こける事もあるから2kがデフォになってる
・同じ図が説明に使われてて、どうやら最初からこの方針らしい

本人達が「チェックしてる」って言うんだからやっぱりそうなんだろう。
一番ありそうな実装は、呼ばれた関数側で最初にチェックする方法で、
つまりローカル変数をスタックに確保するためにスタックポインタからサイズを引く時にチェックする。
これだと、 mov, (sub,) xor, and, jne の追加4命令で(subはチェック無しでも必要)
主にINTパイプで最悪で4cycle、大体の場合はこのあとのLSパイプ(スタック上へのレジスタ待避)に隠れて見えなくなるのではないかと。
だから関数呼び出し毎に0〜4cycのペナルティになる。
ただし、速くなる事はないし、隠れると言っても演算リソースは消費するので、
ハイパースレッディングの場合に相手側のCPUの速度が落ちるのは否めないが。

2k以下にもやれば出来るのだろうけど、やる気がないだけだね。
だから2kで問題なら、コンパイラをいじれば何とかなるのだろうけど、
そこまでやるくらいならRustの方が断然いいね。(後発だから当たり前だけど)
2022/02/27(日) 15:40:03.99ID:F0hGMDSU
関数呼び出しのオーバーヘッドだけど、高階関数らしい高階関数も無いしそういうややこしいことはジェネレーター使う文化だと思ってるな。Genericsが本流になってきたらどうする気だろうもも思ってる。
なお、比較する関数程度の関数はインライン化される。
https://github.com/golang/go/wiki/CompilerOptimizations
2022/02/27(日) 16:13:39.08ID:PVy06kKY
>>9
> 高階関数らしい高階関数も無いし
いや高階関数は普通に出来る。
https://go-tour-jp.appspot.com/moretypes/25
標準やフレームワークにそれを活用する文化がない、という主張なら俺はその辺は知らん。
2022/02/27(日) 16:48:28.74ID:F0hGMDSU
>>10
できるけど、Goではやらんのよ。
凄く纏まってる。
https://zenn.dev/nobonobo/articles/e0af4e8afc6c38b42ae1
2022/02/27(日) 17:20:40.92ID:+yReYAPt
>>6
自己レスです。
Goは1.4からamd64だとスタック2k
https://github.com/golang/go/issues/7514
今回試した1.13.8だと当該コードがCからgoに変わったりして跡形もなかったが、_StackMin = 2048はそのままだった
https://github.com/golang/go/blob/go1.13.8/src/runtime/stack.go
つまり2Mであれば残り1.8Mということで矛盾はない
2022/02/27(日) 17:32:40.97ID:Xl3wWN+O
>>12
1000個立ち上げなんて1桁減らして測定してるからメモリ使用量がわかりにくいような
素直に1万個と10万個で調べて差を見れば1個あたりがはっきりするような
2022/02/27(日) 17:44:54.95ID:+yReYAPt
>>13
時間かかるのが嫌で減らしただけです。。。

ちなみに後ろにウェイト入れて、cat /proc/[pid]/statusした結果
VmHWM: 3296 kB
VmRSS: 3296 kB
VmSwap: 0 kB
なので、rssだけでいいと思います。
2022/02/27(日) 20:47:56.30ID:PVy06kKY
>>11
> 結局のところ素直にforループを書くのがGoには適していて、
> 汎用の型に適用可能な高階関数を実装しようとするのはミスマッチ
これってforEachを実装しようとするのが間違いって事?
或いはmapに高階関数を食わせるのを嫌ってるのか?
いずれにしても、やりたきゃやれよ、だと思うが。

オレオレコーディングルール集だが、全般的に現状肯定的なので、
目指すコーディングではなく、今のGoコンパイラ/ランタイム向けのTips集になってる。
これがどれくらい賛同されるのか不明だけど、革新/改革派からは気に入らない内容だろうよ。
Python出身のようだから、この辺C系の「何でもやっていいけど、結果責任は取れ」文化とは根本的に違うのだろう。
一種類のコードになる事を良しとしてる。

> goroutiineのスケジューラはもちろん依頼処理コストが大きい場合をフォーカスしてチューニングされています。
> ひとつのgoroutineがCPUを占有しすぎないように分散してくれる仕組みがありますが、
> 小さすぎる処理コストをまとめるのは実装者の責任で行わなくてはなりません。
> 小さすぎる処理を頻繁に繰り返すだけであればシングルスレッドの方が速い結果が出るのは当たり前なのです。
これとか、1,000,000goroutine全否定だよね。俺は
Go信者:1,000,000goroutineでも軽いし速い←嘘つくな
GoUser:遅いけど1,000,000goroutineで書きたいんだよ←うむ、遅いと認めるならよろしい。しかし速くなる努力はしたまえ

> Goはデバッガビリティのために末尾再帰最適化をあえて実装していません。
いや怠慢でしかないだろ。再帰がデバッグしづらいとか聞いた事無いわ。

ちな、
> 自作ライブラリの利用方法をメソッドチェインで作ろうとする
考えた事無かったけど、try-catchのメリットってメソッドチェインできることか。
なるほどだからろくにメソッドチェイン出来ないPHPだと何ら意義を感じ取れなかったわけだ、納得。
2022/02/27(日) 21:18:41.64ID:Xl3wWN+O
>>15
Goと同じくtry-catchの無いRustはメソッドチェーンが基本の言語だぜ
関数の返り値が基本的にenumとなってエラーも正常値もメソッドチェーンで処理できるようになってる
■ このスレッドは過去ログ倉庫に格納されています