web-dev-qa-db-ja.com

C ++のマイクロスケールで効果的なコードについて考えることはまだ意味がありますか?

プログラミングのキャリアの早い段階で、ポインターをいじったり、無駄のないコードを作成したり、抽象化レイヤーをできるだけ少なくしてすべてを実行したりすることに夢中になりました。コードは私が言うように非常にCで、金属に近くて賢いものでした。

時間が経ち、経験が豊富になり、コードに対する態度が変わったことに気づきました。

そして、変更されたということは、それが非常に簡単でない限り、私はもはや日常のことを気にしたくないということです。

文字列の連結がある場合、生のポインタを意図的に選択することは決してありません。ものを連結する必要がある場合は、STLコンテナー用の簡単な推測予約を追加することもできますが、事前に割り当てられたバッファー、APIのようなC、キャッシュ、ディスクへのヒットの回避、またはトラッシングを気にしたくありません。すべてのヒープロック、余分なコピーなどを含め、reallocが時々発生する可能性があることは知っていますが、もう気にしません。

たぶん、キャリアの早い段階で、大量の些細なデータを処理するワーカースレッドを使用したクリーンで美しいスキームを考えたのですが、後で、最適化されていないrealloc + copy + realloc + copy全体が見つかったためです。 + realloc + copy +5レイヤーのラッパーはプロファイラーに登録されません。

多分それは私がコンパイラが時々魔法をする方法を見たからです。

しかし、そのような些細なことは合計されます。すべてのコードベースが高次の構造を使用している場合、アプリケーションの速度が遅いという一般的な認識を引き起こす可能性のある、あちこちでの再割り当て、またはコールドディスクヒットが発生する可能性があります。

WTLとMFCのようなものです。または、アプリケーションを起動したときに、アプリケーションがJavaで記述されていることを即座に知る方法。

しかし、それは本当にですか?非常に無駄のないスマートなコードのみを使用しているソフトウェアと、あらゆる場所で汎用コンテナーを使用しているソフトウェアの比較はありますか?

プログラム全体の文字列割り当てが事前予約とスマートムーブを使用する場合と、そのような機能が必要なすべての場所でstring.appendを遅延呼び出しする場合とで、違いを感じることさえありますか?

とにかく実行するのに安価な、そのような単純でよく知られているものの緩和ソリューションを実装しようとしていますか?

コードのすべての行に特別な注意が払われていないという理由だけで、ソフトウェアをブロートウェアに変えることはできますか?

3
Coder

いいえ。プロファイラーは、問題のある場所がどこにあるかをすばやく適切に伝えることができます。

一部のフレームワークに問題がある理由は、問題のある場所がフレームワークまたは仮想マシンの機能にある場合、問題が発生するためです。現実的には、アプリケーションのパフォーマンスを完全に制御できる場合は、気を付けてください。これが、アプリがJavaで起動されたときにわかる理由です。スローダウンがJVMコードにある場合、開発者はそれについて何もできません。ただし、これは一般的なC++開発では問題にならない傾向があります。

言うまでもなく、がらくたを削減し、非常に高レベルのコードをはるかに高速にするコンパイラの能力は、毎年高まっています。

非常に無駄のないスマートなコードのみを使用しているソフトウェアと、あらゆる場所で汎用コンテナーを使用しているソフトウェアの比較はありますか?

バディ、あなたにそれを壊すのは嫌いですが、一般的なコンテナare無駄のないスマートです。それらの主な利点の1つは、これまでに存在したすべてのタイプに対してそれらを書き直す必要がないため、高性能コードを一度記述して再利用できることです。これは、パフォーマンスと信頼性の両方を向上させるDRYの単純なアプリケーションです。999999回自分で書くのは賢いコードではなく、ダムコードです。

6
DeadMG

はい、もちろん、適切な場所で。 C++標準ライブラリなどの適切に調整されたライブラリは、記述が不十分で、現在の10倍遅い場合、信頼できますか?あなたが一緒に働いたすべての人は、前の質問に対して同じ答えを持っていますか?

「Clike」と「clever」は、通常、C++では褒め言葉ではありません。一般的なコンテナは本質的に遅いわけではありません。 C++では、抽象化レイヤーは、実行時にほとんどコストがかからないように記述できます(それが懸念される場合)。

あなたのエネルギー(それが有限であると仮定して)は線の間で均等に分割されるべきではありません。代わりに、速度、サイズ、および/またはリソース使用率が考慮される場合、最も再利用/使用され、より一般的に他の実装の基盤として機能する領域を調べます。優れた実装を再利用して作成する場合は、金属の近くにいるのは簡単です。

ライブラリ、カーネル、ハードウェア、コンパイラなどが変化し、進歩するにつれて、すべてのプラットフォーム/システムに最適なソリューションを予測できるわけではないことに気付くでしょう。常に勝つことはできません。また、これらの大きなバリエーションを考えると、常に勝つことを試みる必要もありません(複数のSSOサイズにstd::stringを使用する実装を常にいじくり回すことを検討してください)。ただし、非効率的な汎用抽象化は、すぐに合計され、適切に実行された効率的な実装の数倍のコストがかかる可能性があります。

結論は、「はい、怠惰に書かれたプログラムは、よく書かれたプログラムよりも簡単に何倍も遅くなり、リソースを消費する可能性があります」です。

描画コード(例として)を現在の10倍高速にする必要がある(または高速にする必要がある)かどうかは、別の問題です。プログラムが小さなワントリックポニーの場合、追加の最適化は必要ないかもしれません。複雑さが増すにつれて、これらの非効率性と不十分なリソース使用率はすぐに非常に重大な問題になります。ユーザーがプログラムをハードウェアの機能の限界に達することが多く、時間やパフォーマンスが重要であることがわかっている場合は、実装への複数のアプローチを検討し、効率的なプログラムを作成するために時間をかける必要があります初期

今日使用しているすべてのプログラムが10倍高速で、使用するメモリがはるかに少なく、優れた並列フォームを使用している場合など、コンピューティングエクスペリエンスがどれほど向上するか想像してみてください。ソフトウェアの複雑さはハードウェアの進歩とほぼ同じ速さで増大しますが、その「成長」は、十分に最適化されていない肥大化と実装でもあります。改善の余地はたくさんあります。

2
justin

言語は、気にすることの意味に大きな違いはありません。コードが現在4.2KiBであるプロジェクトで作業していて、さらに2つの関数を追加し、その結果を4 KiB ROMに収める必要がある場合、サイズを最小化するようにコーディングすると、おそらくlot =意味のある。

一方、16ギガバイトのRAMと2テラバイトのドライブスペースのコストは合計で約$ 200であるデスクトップマシン用にコーディングしている場合は、確認に多くの時間を費やします。コードは最小で最速であり、おそらく見当違いの熱意です。

言語が問題に入る明らかな場所は、C++の場合、目前の正確なタスクにすべてのコードを調整するのではなく、それらの使用に関連するペナルティを最小限に抑えながら、より高いレベルの構造を提供することに多くの作業が費やされていることです。これは常に当てはまるわけではありませんでした。数年前、Alexander Stepanovは、標準テンプレートライブラリでより高いレベルの構成を使用することに関連するペナルティを示すベンチマークを作成しました。ほとんどのテストには、最大限にCスタイルで記述されたコードから、標準のコンテナー、アルゴリズム、およびイテレーターを最大限に活用するコードまで、少なくとも2つまたは3つの「ステップ」がありました。

それが新しいとき、コンテナ/アルゴリズム/イテレータをより完全に使用するためにCスタイルのコードから離れたすべてのステップにペナルティがあったことはほぼ当然のことでした。したがって、最大限にSTLishバージョンに到達するまでに、多くの場合、2倍から5倍遅くなりました(場合によっては10倍近く遅くなりました)。

現在のコンパイラでは、もはやそうではありません-実際、Cのようなコードが実際にSTLコードよりも少し遅いであるということは、もはやそれほど珍しいことではありません(ただし、多くのことを気にするほどではありません)約)。

これはコンパイラベンダーの側で多大な努力を要しましたが、彼らはその作業を行ったので、通常それを利用するのが最も理にかなっています。同等のコードをはるかに迅速かつ簡単に記述できるという事実は便利ですが、その過程で通常はバグを劇的に減らすという事実は、一般的にはるかに重要です。

2
Jerry Coffin