[過去ログ]
Rust part15 (1002レス)
Rust part15 http://mevius.5ch.net/test/read.cgi/tech/1652347700/
上
下
前次
1-
新
通常表示
512バイト分割
レス栞
抽出解除
レス栞
このスレッドは過去ログ倉庫に格納されています。
次スレ検索
歴削→次スレ
栞削→次スレ
過去ログメニュー
511: デフォルトの名無しさん [sage] 2022/06/07(火) 01:10:53.92 ID:YQOkxy3N https://gist.github.com/rust-play/bde9b95f9bfe4de77fad841db30222c7 test bench_1 ... bench: 420,671 ns/iter (+/- 53,102) test bench_fast ... bench: 219,091 ns/iter (+/- 1,147) こんな汚ないことしてまでイテレータになんかしたくないんだけど どうせ次の文句も大体予想付くし http://mevius.5ch.net/test/read.cgi/tech/1652347700/511
512: デフォルトの名無しさん [] 2022/06/07(火) 01:35:52.48 ID:gaZATsj9 この件はRustにとって重要なことだから口を挟むが、 Rustではジェネリックで書いてもmonomorphizationによって各型で書いた時と同じコードになる。 だから標準ライブラリの大半はジェネリックに書かれている。 そしてSomeなどのOptionは最適化できる時は綺麗に消えるため、 BigIntのchecked_addのように常にSomeを返す時も最適化でOptionは消えると考えられる。 いずれも抽象的に書けるのに動かすとC並に速いというRustの長所である。 つまり、>>502の結果が出たことはそれらが実証付けられたことになる。 しかし、以前からジェネリックは無駄とか遅いとかRustの長所に反する主張をする人がいるので気になっていた。 今回もRustのジェネリックは遅いと主張するために、 >>506のように、完全に異なるもの同士を比較したり、 >>511のように、Rcを返すという別仕様のものにしてまで、ジェネリックは遅いと主張し出した。 反Rustか反ジェネリックの立場なのかもしれないが、そういう捏造や詐欺のようなことはよくない。 http://mevius.5ch.net/test/read.cgi/tech/1652347700/512
515: デフォルトの名無しさん [] 2022/06/07(火) 07:03:55.78 ID:/+rlx4fZ >>511 そのコードはイテレータ内部で無理にunwrapしているためこれだけでpanicしてしまう let mut iter = fibonacci_biguint_iter(); let first = iter.next(); let second = iter.next(); 実行結果 thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:23:30 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace これでは反証コードになっていないので ちゃんとimpl Iterator<Item = BigUint>を返すコードを書いたほうがいい >>514 その無駄なcloneとは何? ベンチ>>502のジェネリックコードを含めた5つのコードを見てみたが無駄なcloneは見当たらなかった それらよりもベンチで速いコードが出てこない現状をみると無駄は無いのではないか あと、BigUintを使うまでもない需要も多いのだからジェネリックに書かれたコード一つで十分と感じる http://mevius.5ch.net/test/read.cgi/tech/1652347700/515
526: デフォルトの名無しさん [sage] 2022/06/07(火) 15:36:32.04 ID:glYADNck >>511 俺環の遅いマシンだと6倍近く速くなった この差なら用途によっては汚くする価値が十分あるね まあ実際のプログラムでBigUintのサイズまで一つ一つイテレータで返すような使い方をすることはまずないだろうけど http://mevius.5ch.net/test/read.cgi/tech/1652347700/526
527: デフォルトの名無しさん [] 2022/06/07(火) 15:42:23.15 ID:fRg0KLfu >>511 コードが汚い上にget_mutが失敗してpanicする欠陥コードを恥ずかしげもなく披露できるもんだな http://mevius.5ch.net/test/read.cgi/tech/1652347700/527
537: デフォルトの名無しさん [sage] 2022/06/08(水) 00:55:31.29 ID:QhxBwpDW >>536 複おじの意味がいまだにわからないが ジェネリックよりも速いコードがあるならきちんと示そうぜ >>506はイテレータと関数の異種比較のイカサマ >>511はイテレータ同士の比較へ改善されたがイテレータの中のunwrapでpanicするマガイモノ そんなデタラメばかりしていたら信頼を失うぜ http://mevius.5ch.net/test/read.cgi/tech/1652347700/537
567: デフォルトの名無しさん [sage] 2022/06/08(水) 22:52:52.99 ID:C5b6ywPX このままでは誰も気付かなさそうなのでここでネタばらし >>539のcriterion版ですがこちらで動かすとこうなりました fibonacci_iter_1 time: [7.3605 ms 7.3655 ms 7.3711 ms] Found 9 outliers among 100 measurements (9.00%) 1 (1.00%) high mild 8 (8.00%) high severe fibonacci_biguint_iter time: [7.5944 ms 7.5967 ms 7.5992 ms] Found 2 outliers among 100 measurements (2.00%) 1 (1.00%) high mild 1 (1.00%) high severe 同程度に遅くなってしまいました 理由は>>548の通り、せっかく減らしたcloneをイテレータ化するために戻さざるを得なかったからです 一見非ジェネリックのほうが速い結果が出たのは、criterion版がN=50000としていたのに対して、 test crate版は最初に貼られたN=10000から変えずにやっていたためでした criterion版をN=10000で、test crate版をN=50000で計測してみると大体同じような結果になりました N<2^15あたりまでは非ジェネリックのほうがちょっとだけ速いみたいですが、まあ誤差の範疇かと思います そういうわけで>>539で非ジェネリックのほうが速いと主張したのは嘘です 本気で信じちゃった人はごめんね 最初はcriterionとtest crateの差だと早とちりしたため、ベンチマーク不適切説とか勿体ぶった書き方をしてました >>502で根拠も無く疑いをかけたのに対するカウンターのつもりで黙ってたんですが、不発になっちゃいました まあでもtest crateってwarm upもしないしサンプル数固定だし、その結果ひどい場合だと>>511なんか相対誤差10%超えてるし criterion使ったほうがいいよってのは大筋では間違ってないよね 最後に+=でイテレートするこれだけ貼っとくから 某おじはこれに相当する性能のジェネリックなイテレータが書けるまでそういったクソどうでもいい執着に人を付き合わせるんじゃないぞ https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=76cd0aad53f19888900a4b450fd078c5 http://mevius.5ch.net/test/read.cgi/tech/1652347700/567
619: デフォルトの名無しさん [sage] 2022/06/12(日) 20:47:24.48 ID:nrxswUhC >>577 一般的に参照返すイテレータ類を実装する場合の注意点として、 1. let x0 = x_iter.next(); 2. let x1 = x_iter.next(); 3. ここで x0 の指す値を使う 順にこのような使い方をした時の挙動として、以下4パターンが考えられる A. ✕ 実行時エラーとなる B. ✕ x0の指す値が変化してしまう (次のx1の指す値と同一になってしまう) C. ○ x0もx1もそれぞれ正しい値を指す D. ○ コンパイル時エラーとなる Rcとget_mut()を使った>>511のコードがNGのパターンA.で、これを避けるために、 Rc<RefCell>を使う提案のようだが、それもNGのパターンB.となってしまう Rcとmake_mut()を使えばパターンC.となり、これがRc利用の場合の解となる しかし参照を返すイテレータ自身がmake_mut()でclone()するのは役割として過剰である 切り分けとしてはイテレータを使う側が必要に応じてclone()するのが望ましい そういうコードへ適切に誘導できる道が、コンパイル時エラーで示すパターンD. 具体的には、似非IteratorであるStreamingIteratorを用いるか、 Rust本命のGATsを用いたLendingIterator (=GATs適用後のIterator) を用いると、 clone()が必要な場面ではコンパイル時エラーにより知らせてくれる もちろん普通にnext()ループ内の利用ならばclone()の必要なくコンパイルが通る http://mevius.5ch.net/test/read.cgi/tech/1652347700/619
620: デフォルトの名無しさん [sage] 2022/06/12(日) 20:59:35.22 ID:nrxswUhC 実際に >>618のOverflowingAddAssignを用いてLendingIteratorで実装すると 以下のようになり、GATsを用いている以外は現状のIteratorともちろん同じ形 自己参照を返せるようになった点のみ異なる impl<T: OverflowingAddAssign> LendingIterator for Fibonacci<T> { type Item<'a> = &'a T where Self: 'a; fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> { if self.is_overflow { return None; } if self.is_first { self.is_first = false; } else { self.is_overflow = self.p.overflowing_add_assign(&self.q); std::mem::swap(&mut self.p, &mut self.q); } Some(&self.p) } } is_first処理は >>511のコードでの「iter::once(p.clone()).chain(...」部分であり必須 また、前述のようにBigUintで用いれば is_overflow が常にfalseのため最適化で消えて、 値の更新部分は「self.p += &self.q」のみが残り非ジェネリックと同一コードとなる したがって、上述のコードがどの型でも最善に動作するコードとなるだろう http://mevius.5ch.net/test/read.cgi/tech/1652347700/620
メモ帳
(0/65535文字)
上
下
前次
1-
新
書
関
写
板
覧
索
設
栞
歴
スレ情報
赤レス抽出
画像レス抽出
歴の未読スレ
AAサムネイル
Google検索
Wikipedia
ぬこの手
ぬこTOP
0.040s