- 1 名前:デフォルトの名無しさん mailto:sage [2020/11/16(月) 04:14:40.64 ID:fB5+0hxC.net]
- Goについて扱うスレッドです。
GoはGoogleによって開発された言語です。 公式 https://golang.org 公式ドキュメント https://golang.org/doc/ 公式外パッケージドキュメント https://godoc.org ブラウザ上で試し書き https://play.golang.org ※前スレ Go language part 3 https://mevius.5ch.net/test/read.cgi/tech/1571315884/
- 988 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 20:07:50.21 ID:nWK21oqu.net]
- >>971
優先度がないのはちょっぴり残念ではある …ないよね?
- 989 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 20:31:14.25 ID:kpnhrKVl.net]
- >>969
> 学習コストに対しての性能パフォーマンスが異様に高い Cの方が高いけどな。Goよりも小さい仕様で速い。 あとC#もGUIはゴミだぞ。それ以外がいいからunityを制覇してるが。
- 990 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 21:20:48.95 ID:4mZJSMD8.net]
- >>943
>> それはN:M軽量スレッドだからなし得ることなので、他の言語ができてない以上何とも比べづらい。 RustもM:Nモデルだよ Goと同じく複数の非同期タスクを複数のOSスレッドに割り当て しかもGoとは異なりスタックレスなのでGoよりも軽量タスクを実現しているよ >>951 >> スティーリングまでやるのは他の言語の言語標準機能にはErlangぐらいにしかない。 RustもGoと同じM:Nモデルでワークスティーリングもしているよ Rustでは以下のランタイムを選ぶことができるよ ・1:1モデル (=M:Mモデル、OSスレッドそのまま利用) ・M:1モデル (シングルOSスレッドで並行マルチタスク) ・M:Nモデル[スレッドプール方式] ・M:Nモデル[ワークスティーリング方式]
- 991 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 21:35:40.76 ID:yRlIqUsp.net]
- >>974
それは処理系標準?それとも準標準?
- 992 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 21:58:06.53 ID:kpnhrKVl.net]
- >>974
それ以下と定義が同じだと、一般的には「ワークスティーリング方式」を「スレッドプール」と呼称するよ。(だからC#のもこれのはずだけど) https://tech-blog.optim.co.jp/entry/2019/11/08/163000 Rustで何故あえて方言にしているのかは知らん。 というかワークスティーリングじゃない方のメリットなんてない気がするんだが。
- 993 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 21:58:10.74 ID:nPeFYJEF.net]
- >RustもGoと同じM:Nモデルでワークスティーリングもしているよ
VMじゃないのにどうやって実現してるのかな
- 994 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 21:59:12.46 ID:4mZJSMD8.net]
- >>975
RustはGoと真逆で標準ライブラリとは最小限のものに限る位置付けなので 標準ライブラリには非同期ランタイムを作るための枠組みだけが存在していてランタイム自体は無しだよ これは全ての分野について同じ方針でRustでは標準+準標準(デファクトスタンダード)を使ってプログラミングをするよ
- 995 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 22:13:34.76 ID:4mZJSMD8.net]
- >>976
そこは一般的は話としてまずOSスレッド毎にキューと持つかグローバルにキューを持って割り振るかの2大方式があるよ それぞれに利点と欠点があってそこは省略するけど GoもRustもそのハイブリッド方式となっていて普段はスレッド毎にキューを持って各OSスレッドが独立に効率よく処理だね そしてGoもRustもグローバルにも管理して暇なOSスレッドが生じるとそこへ割り振る(OSスレッドから見るとスティール)するよ 詳細はここで書ききれないほどもう少し複雑だから省略してる点はそれぞれの解説サイトなどを見てね
- 996 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 22:54:22.46 ID:kpnhrKVl.net]
- >>979
Goと同じなら805のリンクの内容と同じだからああそうですか程度。 資料が古いがC#のは以下で確認した。同様にハイブリッドでスティーリングもあり。 (ただ.NET6.0とかだともう変わってそうだが) https://ufcpp.net/study/csharp/misc_task.html 基本グローバルキューで、ただし優先順位はローカルキュー>スティーリング>グローバルキューになってる。 この構造はまあ納得。 > GoもRustもそのハイブリッド方式となっていて普段はスレッド毎にキューを持って各OSスレッドが独立に効率よく処理だね > そしてGoもRustもグローバルにも管理して暇なOSスレッドが生じるとそこへ割り振る(OSスレッドから見るとスティール)するよ 無駄に複雑で余計に遅くなると思うけどね。.NETの方が単純ですっきりしてていい。 グローバルキューから取り出す時の競合を気にしてるのなら、 Goみたいに100,000goroutineとか目指す場合は分かるけど、Rustは基本そうじゃないだろうから、チューニングミスだと思うけど。
- 997 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 23:02:07.46 ID:Gc6jVciw.net]
- Goは別に最速を目指している言語じゃないからね
もし何かのベンチマークが最速になってしまったら逆に驚くよ そのベンチ間違ってるだろ、って。
- 998 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 23:40:35.78 ID:BX4iLvdt.net]
- >>977
VMじゃないと起きる問題点は何? いずれにせよC/C++/RustはVMでもOSでも記述できるのだからそこに不可能は無い >>980 言語に関係なくシステムスレッド間のグローバルな操作はデータ競合回避など一定のコストがかかる だから可能な限り個別にシステムスレッドが動くようにしつつアイドルが出ないよう最小限のグローバル操作 この部分はよほど上位で制約のある仕様としていないならば全ての言語で同じ
- 999 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 23:48:39.58 ID:yRlIqUsp.net]
- >>978
これがなぁ…。過渡期は混ぜるな危険で困らない?そこが不安。 Rustも良いとは思うんだけど、爪切るのにハサミ使ってる気分になる。
- 1000 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 23:59:29.99 ID:kpnhrKVl.net]
- >>982
それはハードによる。 x86はハードウェアでキャッシュコヒーレンシを取ってくれるので実は共有RAMでもコストは安い。 .NETがローカルキューからの取り出しでFIFOとFILOで競合が減るから、というのはそういう事。 Goの場合はARMを見てるのか、MacがARMに乗り換える布石だったのか、 以前からやたら「共有RAMは遅いから使わない」としてきてるが、 ぶっちゃけx86の場合は (書き込み頻度と量によるが、タスクの起動=関数ポインタ1つと引数のポインタ程度なら) OSを利用したチャネル接続よりも共有RAMの方が実は速い。 ここら辺を理解してない奴がグダグダやってるからチューニングし切れてないのだと思うよ。
- 1001 名前:デフォルトの名無しさん mailto:sage [2022/02/26(土) 23:59:34.35 ID:4mZJSMD8.net]
- >>980
>> Goみたいに100,000goroutineとか目指す場合は分かるけど、Rustは基本そうじゃないだろうから、 Rustの非同期タスクはGoroutineよりも更に軽くて Goとは異なりスタックレスなので付加メモリ消費も非同期ランタイムの管理データ分の1タスクあたり64bytesで済みますよ そしてグローバルキュー競合コストの件は>>982のように同じですね
- 1002 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 00:02:30.74 ID:2GGoVw4G.net]
- >>982
問題があると言っているわけじゃなくて、VMやOSじゃなければプリエンプションできないからどうやっているのかなと。
- 1003 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 00:03:38.38 ID:uWHjNeVw.net]
- >>973
Cはお爺ちゃんだから… Cからの乗り換えコストっていう視点でどうかひとつ あ、でも実装系別の頭おかしくなるコンパイルオプションやらバウンダリやらのメモリモデル考えると、Goのほうが実質勝ってないか学習コスト?
- 1004 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 00:11:21.81 ID:uWHjNeVw.net]
- >>973
ちなみに速さやらサイズでは当然にCとかの圧勝だろ普通に 関数呼び出しごとにオーバーヘッドのかかるGoが単純な速度で勝てる道理はない
- 1005 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 00:23:35.14 ID:uWHjNeVw.net]
- >>973
C#というか.Netのwpfは好き 一般的な手法じゃないだろうけど、MVVMのVM部分を単体テストできて(ディスパッチャ細工してメインスレッドで走らせる) []- [ここ壊れてます]
- 1007 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 00:44:59.79 ID:PVy06kKY.net]
- >>985
> Goとは異なりスタックレスなので やたらこれを強調しているが、goでもgoroutineにローカルキュー(=関数ポインタの配列)を用意して、順に食わせれば、 各タスク毎にスタックを用意する必要なんて無くて、普通にエミュレーション出来るよ。 (ただしGo信者的にはこれは負けだからやらないとも思うが) ただこの場合、各タスクが止まらない前提ならこれでいいが、 止めて切り替える分には一般的にはスタック領域が必要になる。 (自動変数を全部ヒープ上に確保すればスタック無しでもいいが、これは遅くなるので多分やってないと思う) ユーザーが確保しなくていいだけで、実際はランタイムかコンパイラが確保してくれてるだけじゃないか?
- 1008 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 00:50:50.94 ID:PVy06kKY.net]
- >>988
> 関数呼び出しごとにオーバーヘッドのかかるGo かからないような気がするが、自信はない。かかる理由って何?
- 1009 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 02:41:36.05 ID:uWHjNeVw.net]
- >>991
Goは関数呼び出しごとにスタックをチェックして、不足してたなら拡大するから 関数ごとの静的な自動変数サイズと比較してるだけだと思うけど、そういう処理のおかげで初期スタックサイズを抑えてる https://postd.cc/performance-without-the-event-loop/
- 1010 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 02:47:33.19 ID:uWHjNeVw.net]
- >>991
「十分な空間がない場合、ランタイムはヒープに対して大きなスタックセグメントを割り当て、現在のスタックの内容を新しいセグメントにコピーし、古いセグメントを解放し、それから関数呼び出しを再開します。」
- 1011 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 03:00:02.25 ID:uWHjNeVw.net]
- >>991
毎回拡張する訳じゃないけどそのためのチェックは毎回走るんで、単にサブルーチンを呼ぶだけの他言語よりは余分な仕事をしている おそらくチェックは必要な回数だけだとは思う(ループ内での呼び出しとかの最適化は考えてないとは思わないから)
- 1012 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 06:52:35.32 ID:+yReYAPt.net]
- compiler explorer(https://godbolt.org/)で、goコンパイル結果を普通のamd64用のアセンブラ見ること出来ないの?(Plan9でなく)
- 1013 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 07:42:28.85 ID:uWHjNeVw.net]
- 次スレ建ててくる
- 1014 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 07:44:00.44 ID:uWHjNeVw.net]
- Go language part 5
https://mevius.5ch.net/test/read.cgi/tech/1645915400/
- 1015 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 07:56:25.05 ID:nXG/aSfD.net]
- >>990
Rustの非同期タスクは内部的には単純な状態マシンとなり何度も再入可能なコルーチンと同じ状況になります その中の変数はRustのクロージャがその環境の変数をキャプチャするのと同じだからもちろんメモリを確保します だからスタックレスで何度も呼べるクロージャみたいな状況でスタック自体はプロセス全体で1本のままとなります もちろんその非同期タスクから他の非同期でない普通の関数を呼べば通常と同じくスタックが伸びて使われていきます 一方でその非同期タスクから他の非同期な関数を呼ぶとその非同期タスクから一旦離脱してスケジューラーへ戻ります 最初に書いたように「単純な状態マシンとなり何度も再入可能なコルーチン」となっているので再び再開できます 以上がスタックレスなのにRustの非同期タスクがメモリの許す限り多く動くことができる仕組みです
- 1016 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 08:07:16.26 ID:c9v4owXb.net]
- ワッチョイ無しかー(´・ω・`)
- 1017 名前:デフォルトの名無しさん mailto:sage [2022/02/27(日) 08:16:41.16 ID:+yReYAPt.net]
- goroutineとC++標準ライブラリのスレッドを比較するために>>957のmain.rsのC++版だけ作ってみた(ループは一桁減らした)
$ cat main.cc #include <thread> #include <chrono> #include <vector> using namespace std; using namespace std::chrono; int main() { vector<unique_ptr<thread>> threads; for (uint32_t i = 0; i < 1000; ++i) { threads.emplace_back( make_unique<thread>([=]{ uint64_t bad_hash = (i * 2654435761) % 200000; this_thread::sleep_for(microseconds(bad_hash)); for (uint32_t _ = 0; _ < 1000; ++_) { this_thread::sleep_for(10ms); } }) ); } for (auto const& t: threads) { t->join(); } return 0; } $ g++ -O3 -pthread main.cc -o main && ./t ./main real 11.04s user 0.93s sys 2.95s rss 11328k $ 結果はmain.rsとほぼ同じで、やはりスレッド起動コストがデカく、rssもデカい
- 1018 名前:1001 [Over 1000 Thread.net]
- このスレッドは1000を超えました。
新しいスレッドを立ててください。 life time: 468日 4時間 2分 1秒
- 1019 名前:過去ログ ★ [[過去ログ]]
- ■ このスレッドは過去ログ倉庫に格納されています
|

|