今日、プログラマは何を「最適化」しますか?[閉まっている]


14

友人のためにシェアウェアをフロッピーにコピーする「古き良き時代」に戻って、かなりの量のアセンブリも使用しました。「マイクロ最適化」という一般的な慣行がありました。1つ少ない命令で表現する方法がわかるまで、アセンブリのラインをじっと見つめていました。数学的に不可能な「もう1つの命令はいつでも削除できます」という格言もありました今日の(ほとんどの)プログラミングでは、小さな一定の要因によるランタイムパフォーマンスの変更は大きな問題ではないため、他の場所での最適化の取り組み?

言い換えると、ベストプラクティスは、価値のあるものを追加しなくなった極端な状態になりますか?そして、代わりに時間を無駄にしていますか?

例:プログラマーは、1つの場所からのみ呼び出されるプライベートメソッドを一般化するのに時間を浪費しますか?時間を無駄にしてテストケースのデータを削減していますか?プログラマーは(まだ)コードの行を減らすことに過度に関心を持っていますか?

私が探しているものには、2つの素晴らしい例があります。(2)わずかなコードの重複も削除します。


これは、「あなたは何のために最適化するのですか?」という質問とは異なることに注意してください。



@Macneil、私は他のプログラマーがどのようにマイクロ最適化するのかわかりませんが、そのための時間はあまりありません。私の同僚も忙しいです(ちょうど2セント)。
ジョブ

@ジョブ:誰かが時間を無駄にして、理由もなくコードを変更するのを見たことがありませんか?幸運を考えてください。以下に、変数名とマイナーコードの複製という2つの優れた例を示します。
マクニール

1
現在の言葉どおり、質問は改善です。投票を削除することはできませんが、数日で期限切れになります。実際、この質問はかなり良い答えを集めています。
ロバートハーヴェイ

1
ところで、任意のベストプラクティスは、それはもはや値を生成するような極端に撮影することができます。
ロバートハーベイ

回答:


22

コードのフォーマット

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.

ああ、そうです、古き良き変数の型と変数名には、一連の変数宣言に独自の列が必要です。ああ!=イニシャライザーの4 行目と4 行目の追加行を忘れてしまいました!
マクニール

[くそ、賛成票を投じるだろうが、私の毎日の制限に達する...]
マクニール

3
私たちの教授は、この方法でアウトアサインメントのコードをフォーマットすることを強制しました。この習慣を取り除くために何年もかかった。
オリバーワイラー

まあ。他の回答では私は笑っていましたが、これは本当に痛いです:-(
Steve314

2
1私はかつてそれが彼のコラム形式のコードを台無しにするので、開発者は自分のコードのconstは、正しい作ることを拒否したライブラリ...と働いた
ディーン・ハーディング

20

私はかつて多くのアセンブラーを書いていました。コンパイラが良くなったというだけでなく、ほとんどのハードウェアがコードのアウトオブオーダー実行専用のロジックをたくさん持っているということです。本当の微妙な問題はスケジューリングであり、ほとんどのコンピューター命令は結果を生成するためにいくつかのマシンクロックを必要とします。したがって、アイデアは、結果を待つのではなく、他の指示をスケジュールして有用なことを行うことでした。また、最新のマシンでは、クロック周期ごとに複数の命令を発行できます。順不同の実行HWを取得し始めた後、ハンドコーディングで優れたパフォーマンスを得ようとすると、マグカップゲームになることがわかりました。まず、故障したハードウェアは、慎重に作成された順序で命令を実行しません。派手な新しいHWアーキテクチャにより、最適化されていないソフトウェアスケジューリングのペナルティが十分に削減され、コンパイラは通常、パフォーマンスの数パーセント以内に収まりました。また、コンパイラーは、アンロール、ボトムローディング、ソフトウェアパイプラインなど、よく知られているが複雑さを発生させるトリックを実装していることもわかりました。それらをすべて使用すると、必要なアセンブラー命令の数が数倍増えます!

おそらくさらに重要なのは、ほとんどのパフォーマンスの問題は、命令の発行率ではなく、データをCPUに取り込むことです。前述したように、メモリレイテンシは数百サイクルになり、CPUはクロック周期ごとに複数の命令を実行できるため、プログラムと特にデータ構造がキャッシュヒット率が非常に高く設計されており、命令がマイクロチューニングされていない限りレベルには見返りがありません。軍のタイプがアマチュアが戦術を語るのと同じように、プロはロジスティクスを語る。パフォーマンスプログラミングは、現在90%を超えるロジスティクス(データの移動)です。現代のメモリ管理には通常複数レベルのキャッシュがあり、仮想メモリページはTLBと呼ばれるハードウェアユニットによって処理されるため、これを定量化することは困難です。また、実際のデータ転送はバイト単位ではないため、アドレスの低レベルのアライメントが重要になります。または64ビットlong-longsでも、キャッシュライン単位で提供されます。その後、ほとんどの最新のマシンには、近い将来に必要となるキャッシュラインミスを予測し、自動プリフェッチを発行してキャッシュに入れるハードウェアがあります。したがって、現実には、最新のCPUではパフォーマンスモデルが非常に複雑で、ほとんど理解できません。詳細なハードウェアシミュレータでさえ、チップの正確なロジックと一致することはないため、正確なチューニングはもはや不可能です。

いくつかのハンドコーディングの場所がまだあります。数学ライブラリ(exp関数など)は、より重要な線形代数演算(行列乗算など)であるため、通常はハードウェアベンダー(Intel、AMD、またはIBM)で働く専門家が通常手作業でコーディングしますが、メガコンピューター会社ごとに一流のアセンブラープログラマーが必要です。


1
タスクはインサイダーの知識とベンダー固有のツール(コンパイラーとプロファイラー)にますます依存しているため、CPUベンダーの外部で作業する人にとって、ハンドコーディングはますます困難になっています。spiral.netはCPU最適化をモデル化し、最適なソリューションの検索を自動化しようとします。
rwong

多くのコンピューター言語は、結果がにレンダリングされる計算に倍精度を使用するのを苦痛にすることにより、プログラマーを無意味に微最適化するように促しますfloat。なんらかの理由で私は推測できませんが、多くの人はこれが良いことだと思っています。
supercat

10

変数またはメソッドに適切な名前を選択する際に(無駄?)時間を費やして、正確な説明だけでなく、言語スタイルも整えることがあります。

作品全体(プログラム)を同じ言語スタイルにしようとすると、もう少し先に進みます。時々私の意見が変わり、本を改訂します。:)

いいえ、それほど時間がかかります。それはかなりまれです。しかし、私は自分のプログラムで良い文法を維持したいです。


3
命名は難しいです。したがって、より良い名前を考えるときは、名前をリファクタリングする必要があります。これは心の努力を捕らえ、うまくいけば「なぜ」も結晶化することに注意してください。

1
これは非常に左脳的なことです(あなたの脳の左側が言語の処理を担当します)。右脳プログラマーとして、私はセマンティクスを心配する時間をはるかに少なくし、すべてのピースがどのように組み合わされるかを心配する時間をより多く費やす傾向があります。
ジェイソンベイカー

7
変数とメソッドの命名は、保守性の重要な部分です。一つは、必要があるので、今から5年という、コードを維持する人はそれで簡単に時間を持って、名前についての時間的な思考を費やしています。
GrandmasterB

@grandmaster:これ以上同意できませんでした。
ロバートハーベイ

4
@ right-brainers:lef-tbrainersのコードを書いてください。そうすればあなたのコードも読むことができます
Juan Mendes

10

時間の複雑さ。私は、プログラムが現実的に遭遇することを知っている何よりも大きい規模で最悪の場合のパフォーマンスのために物事を最適化することにあまりにも多くの時間を費やしています。

他の設計上の決定が現実的な出来事からそれを排除しているときでさえ、「しかしそれその大きな成長を可能にする」骨を手放すにはあまりにも強迫観念です。

ただし、私の防御では、非現実的なものが現実になった場合、最適化はもはや「マイクロ」ではありません。注、不可能とは言いませんでしたが、非現実的です。

もちろん、要件が優先されます。


1
このために沈んだ会社で働いていました。
ヘンリー

2
@ヘンリー-私はそうではなかったと約束します:)
ティムポスト

1
@Henry:あなたはおそらく決して起こらないだろうか、彼らは物事のために最適化し、彼らは無駄な時間を意味しませんでした、彼らはおそらくまで...起こらない「決して」う事について考えてなかったが起こると、それは遅すぎましたか?
ディーンハーディング

2
@Henry:企業が非常にスケーラブルな製品を持っていて、それでも沈没した場合、それは販売とマーケティングの責任です(大量の顧客をターゲットにせず、適切に価格設定しないことによる)。
rwong

1
同社は、1人のユーザーがいない数百万人のユーザー向けのシステムの設計に多くの時間を費やしました。それはマーケティングのせいだったに違いありません。マーケティングを非難しましょう、彼らは馬鹿です。
ヘンリー

8

Java例外ハンドラーをいじるのに何週間もの時間を無駄にしたと思います。

これは、1年に2、3回失敗するコードでは多くの作業です。これは警告または情報ですか?エラーまたは致命的?5分以内にプロセスが再生成されるのは本当に致命的ですか?すべてがまだデフォルト状態にある場合、それは本当に警告ですか?

たくさんのへそを注視し、IOエラーの性質について議論します。ネットワーク経由でファイルを読み取れない場合、それはファイルエラーですか、ネットワークエラーですか?等々。

ある時点で、すべての連結文字列を置き換えたString.formatため、毎年フ​​ァイルエラーが発生しても、ヒープに余分なオブジェクトが含まれることはありません。それは無駄だった。


3
これは重要な仕事です。失敗の価格=エラーメッセージが毎日のWTFで紹介されています。
スティーブ314

7

LOCに過度に関心を持っていると思います。LOC自体はそれほど多くありませんが、ステートメントの数とさらに多くの重複したステートメントがあります。コードの複製にアレルギーがあります。一般的に私はリファクタリングが大好きですが、私がやっていることの約50%でコードが大幅に改善されることはないと思います。


4
「コードの複製にアレルギーがある」ための+1。こちらの返信もご覧ください:Programmers.stackexchange.com/questions/14610/…–
マクニール

考えてみてください-Knuthがgotoについて述べたポイントに関連するループにこの問題があり、構造化コードを書くためにサイクルまたは2つまたはいくつかの重複コードを交換しなければならないことがあります。私非常にまれなケース(最も一般的な=生成コード)でgoto 使用しますが、この障害の私のバリエーションは、些細な非効率性を排除しながらコードを読みやすくしようと無限にループをいじくり回し、時間を浪費しています。
スティーブ314

5

行全体を文字列に読み込んで1つのテイクで文字列を処理するのではなく、行ごとにファイルを読み込みます。

確かに、実行速度に違いがありますが、余分なコード行の価値はほとんどありません。これにより、コードのメンテナンス性が大幅に低下し、コードサイズが増加します。

はい、これはおそらくファイルのサイズが3GBの場合は意味がありませんが、ほとんどのファイルはそれほど大きくありません(少なくとも私が作業しているファイルはそうではありません;-))。


3
3GB以上であっても、64ビットマシンは仮想メモリで処理できます。メモリにマップされたファイルを使用すると、必要になるまでファイルの一部も読み込まれません。心に留めておいてください、それは通常の場合のマイクロ最適化です。
Steve314

3

私がアセンブリ言語を書いていたとき、バイトとサイクルを細かく選択することは理にかなっていましたが、それはかなり前のことであり、コンパイラはそれ以来長い道のりを歩んできました。今は手動で最適化を試みません。

同様に、Cで書くことに切り替えたとき、Cコンパイラよりも良い仕事をするのはかなり簡単でしたが、毎年、BorlandやMicrosoft、または誰かが新しい「n改良版」をリリースして、前の部屋を蹴り上げました。コンパイラが発行している実際のアセンブリコードに注意を払い始め、素敵でタイトなコードを記述していなかった場合、ループを展開したり、変数をループの外に移動したりしないように気をつけました。

現在、私はPerl、Python、Rubyなどのはるかに高い言語で書いています。ループの展開が理にかなっている場合、静的変数をループ外に移動するなど、コンパイラーのトリックを事前に使用しますが、CPUの速度がやや速いため、それほど心配する必要はありません。アプリが予期せずにドラッグしているように見える場合は、プロファイラーを使用して見つけられるものを確認し、改善できるものがある場合は、さまざまな方法でベンチマークを開始して、より速く何かを考えて、それがどのように見えるかを確認しますスケールアップします。

一般に、私は長年の経験に基づいて、コードの書き方を賢くしようとします。


こんにちはGreg、答えてくれてありがとう、しかしプログラマーがランタイムのパフォーマンスを最適化するためではなく、時間を無駄にするために何をするかを探しています。上記の2つの優れた例があります。変数名と、小さなコード重複の削除です。
マクニール

3

マイクロ最適化:並列化可能なもの、または新しいハードウェアで単純に改善できるもののシングルスレッドパフォーマンスを改善します。

10年前のコンピューターで何かが遅い場合、より安価な解決策は、おそらくプログラマーの最適化に時間を浪費するのではなく、新しい高速のコンピューターを購入することです。ただし、最適化の大きな焦点は、ごみの追加コストのような細かい点に悩まされる代わりに、今日入手できる8つのコア、または数年後に入手できる64のコアを使用する方法を見つけることです。コレクション。


2

実行時のパフォーマンスに関するマイクロ最適化は、今日でもクローズドな問題ではありません(あまり一般的ではないかもしれませんが)。リクエストごとに余分なオブジェクトを割り当てたり、余分な関数呼び出しを追加したりするオーバーヘッドはごくわずかであることを時折説明する必要があります。

それとは別に、プログラマーは単純化のために(自分自身も含めて)最適化を最適化するのを見ます。単純さと単純化の違いを説明する必要がなかったので、私はまだどこかで作業していません。


なぜプログラマーでしょう。何か違う?違いは何ですか?
ダンローゼンスターク

@Yar-なぜプログラマーは何と違うのでしょうか?
ジェイソンベイカー

なぜprogrammers.= programmers.stackexchange.comこれらの2つの概念の違いを説明しなければならなかった場所で、あなたが働いたすべての場所と異なるのでしょうか?違いを説明してください。
ダンローゼンスターク

@Yar-どうなるかわかりません。実際、programmers.seのポイントはプログラマーが知識をプールするのを助けることであるので、私の答えによって人々が少なくとも少しは啓発されるようにはならないことを願っています。
ジェイソンベイカー

2
それでは、b / tの単純さと単純さの違いは何ですか?
ダンローゼンスターク

2

私は、本当に必要な原則がない限り、最適化しないでください。そして、私はすべてプロファイル優先の原則に賛成です。そして原則として、必要な違いを生むものだけを最適化します。

それは原則です。しかし、原則は嘘つきです。

私は、頻繁に使用されるライブラリの関数に注意を払う習慣があり、それらは内部ループで多く使用されると思います。そして、別の関数で何かを見つけたとき、それはそれほど頻繁には使用されません...

ああ-そして、「私はそれを書いています-もちろん、それは重要なライブラリです」というロジックがあります。

ああ-ところで。最適化のガイドとしてプロファイラーを使用したことはありません。商用のものにアクセスする必要はありません。gprofを理解する動機を確立することは決してありません。

基本的に、私は偽善者です。これらの原則は他の人にも当てはまりますが、「だれがなぜそんなに遅くてくだらないやり方で書いたのか」と言う人がいるのは怖いです。だから私は本当に自分にそれらを適切に適用することはできません。

でも、ここで言うほど悪くはない。そして、私は自己欺ceptionに完全に免疫があるので、あなたは私がそれについて正しいことを知っています!

編集

私が追加する必要があります-私の主要な愚かなハングアップの1つは通話のオーバーヘッドです。もちろん、どこにでもあるわけではありませんが、内部ループの場合に使用されると思います(問題の客観的な証拠がない場合)。仮想メソッド呼び出しを2回以上行わないように、厄介なoffsetofベースのコードを作成しました。おそらくオプティマイザーがうまく処理するように設計されたコーディングのスタイルではないため、結果はさらに遅くなる可能性があります-しかし、それは賢いです ;-)


+1ああ、はい!このクラスは、アプリケーションの非常に具体的で風変わりなコマンドライン引数を解析しますが、Javadocでフォーマットして完全にドキュメント化することができます。[後で投票する必要があり、私の上限に達しました。]
マクニール

@Macneil-それはDoxygenです、知っています。すべてのオプションがオンになっているので、すべての小さな機能が非常に詳細な「文書化」され、12のかなりのGraphVizグラフが完成します。本当に私のコードがどれだけ重要かを誰もが理解するのを本当に助けてくれます-そして、プリントアウトはかなり大きなオフィスブロックを壁紙にできます。
スティーブ314

1

コンピュータがマイクロ秒単位で測定されるクロック時間、キロバイト単位で測定されるメモリ、およびプリミティブコンパイラを使用していた昔は、マイクロ最適化は意味がありました。

現在の世代のコンピューターの速度とサイズ、および現在の世代のコンパイラーの品質により、通常、マイクロ最適化は時間の無駄です。例外は、計算量の多いコードから絶対に最大のパフォーマンス得る必要がある場合、またはリソースが非常に限られている組み込みシステム用に記述している場合です。

しかし、ランタイムパフォーマンスを最適化するためではなく、プログラマが時間を無駄にするために何をするかを探しています。

TwitterとFacebookが思い浮かびます:-)


こんにちはスティーブン、それはマイクロ最適化に関する素晴らしい解説ですが、現代の同等物はありますか?[FacebookとTwitterは、行き過ぎた「ベストプラクティス」ではありません。]
マクニール

まだ理にかなっています。クロック時間は桁違いに小さいかもしれませんが、コードは桁違いに大きいです
...-hplbsh

@Stuart-それは、マイクロ最適化するためのより多くのコードの桁があることを意味します...それは単にスケーリングしません。
スティーブンC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.