- RustとCの性能比較は、「すべての条件が同一である」という前提をどう定義するかによって変わる複雑な問題である
- インラインアセンブリについては、両言語とも同一のアセンブリコードを生成できるため、言語自体の速度差はない
- 構造体のメモリレイアウトでは、Rustはフィールドの並べ替えによってより小さいサイズにできるが、
#[repr(C)] 属性でCと同じレイアウトにすることも可能である
- ランタイム検査と開発者の振る舞いの違いにより、実際のプロジェクトではコード構造と性能が変わりうる
- 結論として、言語自体の限界による性能差はなく、プロジェクトと開発者の要因によって結果は変わる
問題提起と前提の曖昧さ
- Redditで提起された**「同じ条件ならRustはCより速くなりうるのか」**という問いが出発点
- **「すべての条件が同一」**という表現自体が、言語比較では非常に定義しにくい概念である
- 性能比較は言語の違いだけでなく、コードの形、開発上の判断、コンパイラ最適化によっても左右される
インラインアセンブリの比較
- Rustは言語レベルでインラインアセンブリをサポートし、Cはコンパイラ拡張機能としてこれを実装する
- 両言語とも
rdtsc 命令を使う同一の例を書ける
rustc 1.87.0 と clang 20.1.0 で生成されたアセンブリは完全に同一の形で出力される
- この事例は言語の性能差を示すものではないが、RustがCと同等の低レベル制御を行えることを証明している
構造体レイアウトの違い
- Rustの構造体はフィールドの並べ替えによってメモリ使用を最適化できる
- 例ではRustの構造体は16バイト、同等のC構造体は24バイトと計算される
- Cでは同じサイズを得るためにフィールド順を手動で変更する必要がある
- Rustで
#[repr(C)] 属性を使えば、Cと同一のメモリレイアウトを強制できる
社会的・開発者要因
- Rustの安全性検査のおかげで、開発者がより積極的な最適化を試みられる事例がある
- MozillaのStyloプロジェクトでは、C++で2回の並列化の試みが失敗したが、Rustでは成功裏に実装された
- 同じプロジェクトでも、言語と開発者の習熟度によって結果コードの性能と安定性は変わりうる
- 初級開発者と専門家、また言語への習熟度によって「同じ作業」の結果が異なるため、単純比較は難しい
コンパイル時とランタイムの検査
- Rustの多くの安全性検査はコンパイル時に行われるが、一部はランタイム検査として残る
- たとえば
array[0] へのアクセス時、Rustは境界検査を行うが、Cは行わない
- Rustで
get_unchecked() を使えば、Cと同じ動作を得られる
- コンパイラが安全性を証明できる場合、両言語とも検査を最適化で除去できる
- こうした違いはコードの書き方に影響し、結果として性能差を生む可能性がある
結論
- Cが「最速の言語」だと仮定しても、Rustが同等の性能を出せない理由はない
- 言語自体の限界よりも、プロジェクトの特性、開発者の力量、時間的制約などの外部変数が性能差を決める
- したがって、「RustはCより速いのか?」という問いは、言語比較というよりエンジニアリング文脈の問題として解釈される
9件のコメント
Hacker Newsの意見
要約すると、最高速度はほぼ同じだが、実際のコードでは差が大きい
特に マルチスレッド が大きな変数だ。Rust はスレッドを使うかどうかに関係なく、すべてのグローバル変数がスレッドセーフでなければならず、borrow checker がメモリアクセスを共有か変更のどちらか一方に制限する
そのため Rust ではマルチスレッドコードを書くことがほぼ前提のようになっている。一方 C では、スレッド生成自体がプラットフォーム互換性の問題やデバッグリスクのために負担が大きい
C でスレッドを組むのは難しくないが、Rust の
std::thread::spawn(move || { ... });よりは面倒だメモリ安全性よりも、言語の 並行性モデル のほうが大きな影響を与えている。Go はメモリ安全でなくても
go f()で簡単に並列化できる個人的には Go で heisenbug をより頻繁に見てきた
#pragma omp forを 1 行書けば C でも簡単に並列化できるRust の traits によって、より高速で柔軟な抽象化を作れる
C ではマクロや関数ポインタで真似できるが、Rust では呼び出し側が 動的ディスパッチ か 静的ディスパッチ かを選べる
組み込み環境では関数ポインタがキャッシュを乱して性能を落とすが、Rust の traits はインライン最適化が可能なので、はるかに効率的だ
Rust でも C でも、結局はバイト単位で扱うことになり、最近は バイナリパッチ ツールも充実していて活用しやすい
Box<dyn Trait>を使えば、呼び出し側は動的ディスパッチを強制されるimpl Traitを使えば、呼び出し側に選択肢が残る個人的には Rust、C、C++ はほぼ同じ 低レベル言語の系譜 なので、性能差はごくわずかだと思う
Rust の 厳格な aliasing 規則 は最適化に有利で、C/C++ の UB(未定義動作) は性能のために存在する
また Rust と C++ の ジェネリクス は C よりはるかに強力で、たとえば
qsort()の代わりにテンプレートベースのソートならインライン最適化がしやすいこうした言語間の 速度論争 はたいてい無意味だと思う
言語そのものより コンパイラ実装 が性能を左右する
Rust、C、C++ はいずれも 低水準言語 だが、「速い」とは何を意味するのかが重要だ
専門家が最適化したコードの最高速度を指すのか、それとも 平均的な開発者が予算内で高速なコードを書ける確率 を指すのかで違ってくる
ただし手作業で最適化すれば、言語の差はほとんど消える
それでも Rust は 高速なコードを書きやすい言語 という点で少し優位がある
Rust の利点は マルチスレッド と スタック割り当て だと思っていた
所有権モデルのおかげで、C/C++ より多くのものをスタックに載せられるため、malloc/free のオーバーヘッド を減らせる
こうした話題は感情的な議論になりがちなので、具体的な数値より 考え方の違い を扱いたかった
言語の「速さ」を論じるときは、2 つの点を見るべきだ
Rust と C はランタイムチェックがほとんどないので、Python や JS より速い
ただし Rust は aliasing 情報 をよりうまく伝えるため、最適化の余地がある
デバッグモードでは Ruby 並みに遅いが、リリースモードでは C 並みの速度が出る
C より C++ や Rust のほうが コンパイル時機能 が豊富で、高速なコードを書きやすい
たとえば このコード は C ではほぼ不可能だ
C では re2c のような 外部ツール が必要だ
アセンブリは C 標準の一部ではないので Rust と直接比較しにくく、Rust はむしろ GCC プロジェクト に近い性格だ
どの言語が「速い」かは結局 実装と文脈 によって変わる
言語そのものの速度より、コンパイラとハードウェアの組み合わせ のほうが大きく影響する
平均的にどの言語が最も速いのかは分かりませんが、ばらつきはC++がいちばん大きい気がします。
組み込みでは、ハードウェアのキャッシュラインサイズまで考慮してコーディングしますよね。結局のところ、プログラマが言語の上でどこまで極限の最適化をできるか、そして標準ライブラリやコンパイラの性能の問題だと思います。どちらも低水準をサポートしている以上、わずかなオーバーヘッドの違いは無視できる程度ではないでしょうか。なので、それほど意味のある論争ではない気がします。極限の最適化が必要なら、結局は人間の介入が必要です。コンパイラは思うほど完璧ではないので。
Rust は C よりも C++ の代替になると思う。C は、コンパイラが生成するコードを事実上予測できる唯一の(あるいは最後の)言語…
Zigも悪くないですよ…(泣)
書いているうちにAI要約調に (泣)
わざとそうされたのではないですか、ふふ
それはコンパイラの性能次第です。
同じコードをアセンブルしてみれば分かるでしょう。
ffmpegのおじさんたちは、RustがCより速いわけではないと考えているみたいですね(笑) https://www.memorysafety.org/blog/rav1d-perf-bounty/