最適化_(情報工学)
[Wikipedia|▼Menu]

コンピュータ関連において最適化(: Optimization)という語は、最適化問題のそれを指すことも多いが、ここでは、コンパイラ最適化などに似た話題について説明する(「情報工学」と記事名には付いているが、全く information engineering の話題ではない)。コンピュータシステムは、主としてコストパフォーマンス上の理由から、効率的に(efficiently)動作することが望ましいことが多い。例えば、コンパイラ最適化は、高速化のためだったり、メモリの使用量を削減するためだったり、電力消費を抑えるためだったりする。最適化の対象となるシステムは、1つのプログラムの場合もあるし、複数のコンピュータの場合もあるし、インターネットのようなネットワーク全体の場合もある。

"optimization" という単語の語源は "optimal"(最適な、最善な)と同じだが、最適化によって真に最適なシステムとなることは稀である。最適化されたシステムは一般にある面でのみ最適となる。プログラムの実行時間を削減するためにメモリ使用量を増やしてでも実行時間を最適化したり、逆にメモリが少ないシステムで実行時間が長くなることを覚悟してメモリ使用量が少ないアルゴリズムを選んだりする。あらゆる場合に最適な方法や設計は存在しないので、技術者は最も重要と思われる観点での最適化のために妥協点を探る。さらに、ソフトウェアを最適にする(それ以上どうやっても最適化できない状態にする)のに要する労力は、その最適化されたシステムを利用することで得られる利益よりも大きい。従って、最適化の工程は最適解に到達する以前に終了させられるのが普通である。幸いなことに、効果の大きい改善は最適化工程の初期に現れることが多い。

最適化は様々なレベルで行われる。最も高いレベルの最適化は設計段階に行われる。設計が最適化されていれば、実装でも効率的なアルゴリズムを利用でき、品質のよいコードになるという利点がある。コンパイラ最適化を使えば、実行ファイルがさらに最適化される。最も低いレベルでは、コンパイラを使わずに人間がアセンブリ言語で最適なコードを書く。コンパイラ最適化の技術の進歩と最近のCPUの複雑さのため、コンパイラよりも最適なコードを人間が書くには大変な技能を要する。そのため、このような最適化を行うプロジェクトは滅多にない。最適化は例外的なケースを考慮しつつ、複雑な妥協点を探ることが多い。従って最適化されたプログラムはプログラマが理解できないほど難解になることも多い。可能であれば等価であることが保証されながらプログラムを変形させるなどの手法でバグの可能性をゼロにすべきだが、できない場合、できていないコードではバグを多く含む危険性がある。
基本

計算処理には効率の異なる複数の実行方法が存在することが多い。例えば、以下のC言語コードは、1 から N までの整数の総和を計算するものである。int sum = 0;for (int i = 1; i <= N; i++) sum += i;printf("sum: %d\n", sum);

演算でのオーバーフローが発生せず、かつ、N >= 0 ならば、これを以下のような数学的な式で書き換えることもできる。int sum = (N * (N + 1)) / 2;printf("sum: %d\n", sum);

最適化(特に自動的に行われる最適化)は、機能的に等価でより効率的な方法を選択することに他ならない。しかし、効果の大きい性能改善は無駄な機能を省いて実際の問題に集中することで実現されることも多い。

最適化は必ずしも自明で直観的なものとは限らない。上の例で「最適化」されたバージョンは N が小さければオリジナルよりも性能が悪い可能性がある。これは、そのコンピュータでの加算とループの性能と乗除算の性能の関係に依存する。
トレードオフ

最適化は一般に性能の様々な観点(実行時間、メモリ使用量、ディスク使用量、帯域幅、電力消費など)の一部だけを改善する。そこには何らかのトレードオフがあり、ある観点を犠牲にして別の観点を最適化することになる。例えば、キャッシュを大きくすれば実行時の性能は改善されるが、キャッシュも含めたメモリ消費は増大する。その他の典型的なトレードオフとしては、コードの読みやすさとコンパクトさ、デバッグのし易さ(命令の入替や冗長なコードの削除、関数インライン展開などの最適化の結果として、ソースコードとバイナリコードの間での対応関係が付け難くなったりブレークポイントを設定できる行数が減ったり、ブレークポイントでブレークしなかったり、とデバッグ時にコードの振る舞いや変数の変化が理解しにくくなる)などがある。

プログラマが最適化を行う際に、一部の処理を最適化するには他の処理の効率を悪くしなければならないという決断をせまられることがある。このようなトレードオフは技術的でない理由で必要となることが多い。例えば、競合他社が発表したベンチマーク結果に勝つため、通常のソフトウェアの効率が悪くなるとしてもベンチマークをより効率的に実行する最適化を施すといった場合である。
その他の分野

この記事ではなく、「最適化問題」の記事にある内容についての話題を混同する者も多い。

プログラミングでは、より効率的なソフトウェアを生成するため、アーキテクチャに合わせたコンパイラの設定をしたり、そのアーキテクチャにあわせたコード修正を施すことを最適化と呼ぶこともある。

典型的な問題は様々な解法があり、プログラミングでは「十分によい」解だけを考慮する。
ボトルネック

最適化ではボトルネックを見つける必要がある。ボトルネックとは、化学反応における律速段階などのアナロジーで説明されるが(反応速度#律速段階も参照)、全体を「流れ」とした見た時に最もその流れが妨げられていて、全体の速さがその部分の速さで決まっている、という部分のことである。また近年のように並列実行のコストが下がっている場合、最適化に苦労するよりも問題が並列化可能であるならそちらで解決したほうが手っ取り早いということもある。並列化に関する法則としてはアムダールの法則グスタフソンの法則がある。

またボトルネックに関する経験則として、全体の1%?25%のコードが75%?99%のリソース(CPU時間、メモリ)を消費する(パレートの法則も参照)、といったような傾向がある(当然、ザルに書いたコードほどその傾向は激しく、予めよくわかっている対象について綿密に計画され、さらに改良が重ねられたコードであれば逆になる)。ボトルネックとなっている処理が非常に単純でそれ以上最適化しようがない場合もある。プログラムとは別のレイヤ、例えば、コンピュータ・アーキテクチャに原因があることもある。

アーキテクチャに関わる設計はシステムの性能をほとんど決定づける。アルゴリズムの選択は設計の中でも最も効率に影響が大きい。複雑なアルゴリズムやデータ構造は多量の処理には適しているが、単純なアルゴリズムは少量のデータ処理により適している。複雑なアルゴリズムでは設定や初期化に時間がかかり、データが少量の場合に効果が薄れるためである。

場合によっては、メモリを追加することでプログラムが高速化されることがある。例えば、フィルタは入力を1行ずつ読み込んで、結果を即座に出力する。この場合、1行を読み込むだけのメモリがあれば十分だが、そのような方式での性能は一般にあまりよくない。


次ページ
記事の検索
おまかせリスト
▼オプションを表示
ブックマーク登録
mixiチェック!
Twitterに投稿
オプション/リンク一覧
話題のニュース
列車運行情報
暇つぶしWikipedia

Size:28 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)
担当:undef