ホームページ >バックエンド開発 >C++ >CとCは本当に速いですか?

CとCは本当に速いですか?

Susan Sarandon
Susan Sarandonオリジナル
2024-12-07 09:25:13954ブラウズ

C and C   are really so fast?

私がずっとプログラミングに取り組んでいると、速度の標準は C と C だと聞きます。最速中の最速で、アセンブリ コードに直接コンパイルされ、速度において C や C に匹敵するものはありません。そして、その一般的な信念に異議を唱える人は誰もいないようです。

コンピューティングパフォーマンス

数値を使った算術演算は、明らかに、C では他の言語よりも大幅に高速に動作する必要があります。でもそうですか?
少し前に、私は速度の実際の違いがどれほど大きいかを確認するために、さまざまな言語用の一連の簡単なベンチマークを作成することにしました。
アイデアは単純でした。単純な計算を使用して、ゼロから始まる 10 億の整数の合計を求めるというものです。一部のコンパイラ (rustc など) は、このような単純なサイクルを数式に置き換えます。もちろん、これは一定時間で評価されます。そのようなコンパイラでそれを回避するには。 ビット単位またはなど、数値を使用したコスト演算でも同様の操作を使用しました。
結果が出た後、とても驚きました。私の世界観はひっくり返り、プログラミング言語の速度について自分が知っていたすべてを再考する必要がありました。
以下の表に私の結果が表示されます:

Linux 64 ビット1.1 GHz CPU、4GB RAM

言語 コンパイラ/バージョン/引数 時間 Rust (
Language compiler/version/args time
Rust (bitwise or instead of ) rustc 1.75.0 with -O3 167 ms
C gcc 11.4.0 with -O3 335 ms
NASM 2.15.05 339 ms
Go 1.18.1 340 ms
Java 17.0.13 345 ms
Common Lisp SBCL 2.1.11 1 sec
Python 3 pypy 3.8.13 1.6 sec
Clojure 1.10.2 9 sec
Python 3 cpython 3.10.12 26 sec
Ruby 3.0.2p107 38 sec
の代わりに ビット単位または ) rustc 1.75.0 (-O3 あり) 167 ミリ秒 C gcc 11.4.0 (-O3 あり) 335 ミリ秒 NASM 2.15.05 339 ミリ秒 行く 1.18.1 340 ミリ秒 Java 17.0.13 345 ミリ秒 一般的な Lisp SBCL 2.1.11 1 秒 Python 3 pypy 3.8.13 1.6 秒 Clojure 1.10.2 9 秒 Python 3 cpython 3.10.12 26 秒 ルビー 3.0.2p107 38 秒 テーブル>

ここにあるすべてのテスト ソース:
https://github.com/Taqmuraz/speed-table

ご覧のとおり、C は Java よりもそれほど高速ではなく、その差は約 3% です。また、他のコンパイル言語は算術演算のパフォーマンスが C に非常に近いことがわかります (Rust はさらに高速です)。 JIT コンパイラ でコンパイルされた動的言語は、より悪い結果を示します。主な原因は、算術演算がそこで動的にディスパッチされる関数にラップされているためです。
JIT コンパイラなしで解釈された動的言語は最悪のパフォーマンスを示しますが、驚くべきことではありません。

メモリ割り当てパフォーマンス

あの惨敗の後、C ファンは、GC を要求せずにシステムから直接メモリを割り当てるため、C でのメモリ割り当てが非常に高速であると言うでしょう。
今後も、コンテキストに応じて、GC という用語を ガベージ コレクターマネージド ヒープ の両方として使用します。
では、なぜ人々は GC がとても遅いと考えるのでしょうか?実際、GC には事前に割り当てられたメモリがあり、割り当ては単にポインタを右に移動するだけです。ほとんどの場合、GC は、C の memset と同様に、システム コールを使用して割り当てられたメモリをゼロで埋めるため、一定の時間 がかかります。 C でのメモリ割り当てには、システムとすでに割り当てられているメモリに依存するため、不定の時間がかかります。
しかし、この知識を考慮しても、Java からそれほど良い結果は期待できませんでした。これは次の表に示すとおりです。

1.1 GHz 2 cores, 4 GB RAM
Running tests on single thread.
Result format : "Xms-Yms ~Z ms" means tests took from X to Y milliseconds, and Z milliseconds in average
1.1 GHz 2 コア、4 GB RAM 単一スレッドでテストを実行しています。 結果の形式 : 「Xms-Yms ~Z ms」は、テストに X から Y ミリ秒、平均で Z ミリ秒かかったということを意味します テーブル>

整数配列の割り当て

integers array size times Java 17.0.13 new[] C gcc 11.4.0 malloc Common Lisp SBCL 2.1.11 make-array
16 10000 0-1ms, ~0.9ms 1-2ms, ~1.2ms 0-4ms, ~0.73ms
32 10000 1-3ms, ~1.7ms 1-3ms, ~1.7ms 0-8ms, ~2.ms
1024 10000 6-26ms, ~12ms 21-46ms, ~26ms 12-40ms, ~7ms
2048 10000 9-53ms, ~22ms 24-52ms, ~28ms 12-40ms, ~19ms
16 100000 0-9ms, ~2ms 6-23ms, ~9ms 4-24ms, ~7ms
32 100000 0-14ms, ~3ms 10-15ms, ~11ms 3-8ms, ~7ms
1024 100000 0-113ms, ~16ms 234-1156ms, ~654ms 147-183ms, ~155ms
2048 100000 0-223ms, ~26ms 216-1376ms, ~568ms 299-339ms, ~307ms

1 つの整数フィールドを備えたクラス Person のインスタンスを割り当てます。

how many instances Java 17.0.3 new Person(n) C g 11.4.0 new Person(n)
100000 0-6ms, ~1.3ms 4-8ms, ~5ms
1 million 0-11ms, ~2ms 43-69ms, ~47ms
1 billion 22-50ms, ~28ms process terminated

ここにあるすべてのテスト ソース:
https://github.com/Taqmuraz/alloc-table

そこで私は合計 4 つの言語 (C、C、Java、Lisp) をテストしました。また、 GC を使用した言語は、 C や C よりもはるかに厳密にテストしましたが、常に良い結果を示します。たとえば、Java では仮想関数呼び出しを通じてメモリを割り当てているため、静的に最適化されない可能性があります。また、Lisp では割り当てられた配列の最初の要素をチェックしているため、コンパイラは割り当て呼び出しをスキップしません。

メモリの解放

C ファンは依然として自分たちの信念を守ろうとする動機を持っているため、「はい、メモリの割り当ては速くなりますが、その後は解放する必要があります。」と言います。
真実。そして突然、GC は C よりも速くメモリを解放します。しかし、どのようにしてメモリを解放するのでしょうか? GC から 100 万回の割り当てを行ったが、その後、プログラム内で参照されるオブジェクトが 1000 個だけになったと想像してください。そして、それらのオブジェクトがその長いメモリ全体に分散されているとします。 GC はスタック トレースを実行し、これら 1000 個の「生きている」オブジェクトを見つけて、それらを前の世代のヒープ ピークに移動し、最後のオブジェクトの後にヒープ ピーク ポインタを置きます。以上です。
したがって、割り当てるオブジェクトの数に関係なくGCの作業時間は、後に保持するオブジェクトの数によって決まります。
そして、それとは逆に、C では割り当てられたメモリをすべて手動で解放する必要があるため、メモリを 100 万回割り当てた場合は、同様に 100 万回の解放呼び出しを行う必要があります (そうしないとメモリ リークが発生します)。つまり、GCO(1)-O(n) と C の O(n) またはそれより悪い (n) に対するものです。は以前に発生した割り当ての数です。

まとめ

そこで、C および C に対するガベージ コレクション言語の勝利を確固たるものにしたいと考えています。概要表は次のとおりです:

要求 GC を使用する言語 C/C 算術
demands languages with GC C/C
arithmetic fast with JIT fast
allocating memory fast O(1) slow
releasing memory fast O(1) best case, O(n) worst case O(n) or slower
memory safe yes no
JIT による 高速化 速い メモリを割り当てています 速い O(1) 遅い メモリを解放しています 高速 O(1) 最良の場合、O(n) 最悪の場合 O(n) またはそれより遅い メモリセーフ はい いいえ テーブル>

これで、ガベージ コレクションは必要悪ではなく、私たちが望むだけの最高のものであることがわかるかもしれません。それは私たちに安全性パフォーマンス両方をもたらします。

Cへのトリビュート

C は私のテストでは悪い結果を示しましたが、依然として重要な言語であり、独自の応用分野があります。私の記事はCの拒絶や抹殺を目的としたものではありません。 C は悪くはありませんが、人々が思っているほど優れているわけではありません。多くの優れたプロジェクトが崩壊したのは、一部の人が Java の代わりに C を使用することを決めたという理由だけです。たとえば、C の方がはるかに高速で、Java はガベージ コレクションのせいで信じられないほど遅いと言われてきたためです。非常に小さく単純なプログラムを作成する場合には、C が適しています。ただし、C を使用して複雑なプログラムやゲームを作成することは決してお勧めしません。

Cは違うよ

C は単純ではなく、柔軟性がなく、構文が多重定義されており、仕様が複雑すぎます。 C でプログラミングすると、自分のアイデアを実装することはできませんが、90% の確率でコンパイラ エラーやメモリ エラーと戦うことになります。
この記事は C を拒否することを目指しています。速度とパフォーマンスは人々がソフトウェア開発でこの言語を使用するための言い訳にすぎないからです。 C を使用すると、時間、プログラムのパフォーマンス、精神的健康で対価を支払うことになります。したがって、C と他の言語のどちらかを選択する場合は、最後の言語を選択してください。

以上がCとCは本当に速いですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。