お使いのRwLock
はstd::sync
モジュールが提供しているものでしょうか? もしそうなら、それによってOSで差がつくかもしれません。
一般的な話として、Reader-Writerロックを実装する際、Readerロックの要求とWriterロックの要求が同時にあったときに、どちらを優先するか決める必要があります。
たとえば、Readerロックを優先する場合は、以下のようになります。
- すでに1つ以上のReaderロックが有効なとき、たとえ待機中のWriterロックがあったとしても、後から来たReaderロックが優先される。
- 全てのReaderロックが解放されるまで、Writerロックは待たされる。
Rustのstd::sync::RwLock
は、この優先順位ポリシーを自身では定義(実装)せず、OSの実装に依存するようになっています。
https://doc.rust-lang.org/stable/std/sync/struct.RwLock.html
The priority policy of the lock is dependent on the underlying operating system’s implementation, and this type does not guarantee that any particular policy will be used.
そして、私の記憶が正しければ、Linux上ではReaderロック優先になっています。
ここからは想像ですが、Windows上では別の優先順位ポリシーが採用されているのではないでしょうか。そして、質問者様のワークロードは、たまたま、Readerロック優先の方が効率的に動くのかもしれません。
このようなことが起こっているかの確認方法の一つに、優先順位ポリシーがOSに依存しないReader-Writerロックの実装を試してみることがあります。たとえば、parking_lotクレートのRwLock
はeventual fairnessというポリシーを採用しており、どのOS上でも同じように動作します。
https://docs.rs/parking_lot/0.12.1/parking_lot/type.RwLock.html#fairness
This rwlock uses eventual fairness to ensure that the lock will be fair on average without sacrificing throughput. This is done by forcing a fair unlock on average every 0.5ms, which will force the lock to go to the next thread waiting for the rwlock.
これを使ってみて、LinuxとWindowsでどのように性能が変わるかを確認してみるのはいかがでしょうか? もしstd::sync::RwLock
が理由なら、parking_lot::RwLock
を使うことで性能差がなくなるかもしれません。
追記 2022-10-29
std::sync::RwLock
の優先順位ポリシーについて、追加情報があります。
- Linux版は今年6月にリリースされたRust 1.62からwriterロック優先に変更されたそうです。
- Windows版は最近はOSが提供するSlim Reader/Writer (SRW) Locksを内部で使用しているそうです。
- このチケットに書かれていました:https://github.com/rust-lang/rust/issues/93740
- Microsoftのドキュメントによると、SRWは優先順位ポリシーを持たない(ロックが取得される順序を保証しない)ようです。
- "There is no guarantee about the order in which threads that request ownership will be granted ownership; SRW locks are neither fair nor FIFO"
また、家族のWindows PCを借りて自分でも試してみました。(普段私はMacを使っていて、Windowsのことはあまり分かりません)
- Windows 11 Home
- WSL 2 Ubuntu 22.04
- Intel Core i7-12700Fを搭載しており、4つのEコア(高効率コア)と8つのPコア(高性能コア)がある
- Rust 1.64.0
- テストプログラムには、Rustで書かれたBitonic sorter(並列ソートアルゴリズムのひとつ)を使用
以下のことが分かりました。
- 電源オプションの電源モードがデフォルトの「バランス」に設定されていると、マルチスレッド、シングルスレッドに関係なく、WSLに対して性能が落ちる
- シングルスレッドで1.6倍の時間がかかった
- マルチスレッドで4.5倍の時間がかかった
- Eコア(高効率コア)しか使われていない!
- 電源モードを「最適なパフォーマンス」に変更したところ、WSLに近い性能が出るようになった
- シングルスレッドで1.1倍の時間がかかった
- マルチスレッドで1.05倍の時間がかかった
- 全コア使われているが、クロック周波数がやや低い
Windows 11 Homeでは電源オプションに応じたCPUスロットルがかかっており、パフォーマンスを優先する設定にしても完全には解除されないのかもしれません。
追記その2 2022-10-29
- テストプログラムには、Rustで書かれたBitonic sorter(並列ソートアルゴリズムのひとつ)を使用
そのプログラムはロック競合をほとんど起こさないものだったので、あまり参考にならなかったかもしれません。別のプログラムで試してみました。電源モードは「最適なパフォーマンス」に設定しています。
- 128スレッドで並行処理し、
- ロック競合が多発するケースではWindowsの方がLinxuよりも1.7倍ほど遅い
- 多発しないケースではWindowsの方がLinxuよりも1.6倍ほど速い
性能差があることが確認できましたが、このプログラムはかなり複雑なことをしており、調査には適さないです。調査用にシンプルなプログラムを書いて調べてみたいと思います。(途中経過はRustの日本語Zulipチャットに書いていきます)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/10/28 12:17
2022/10/28 20:25
2022/10/29 02:51