0

私の場合、C# を使用していますが、質問の概念は Java にも当てはまります。うまくいけば、答えは両方の言語をカバーするのに十分一般的です. それ以外の場合は、質問を 2 つに分割することをお勧めします。

私はいつもどちらがより良い習慣であるかを考えてきました。

コンパイラは、パフォーマンスが「最初の」コードと同じくらい良好になるように、「2 番目の」コードを強化しますか?

「より良いパフォーマンス」と「最適化された」コードを同時に取得するために回避できますか?

冗長/パフォーマンス向上コード:

string name = GetName(); // returned string could be empty
List<string> myListOfStrings = GetListOfStrings();
if(string.IsNullOrWhiteSpace(name)
{
    foreach(string s in myListOfStrings)
        Console.WriteLine(s);
}
else
{
    foreach(string s in myListOfStrings)
        Console.WriteLine(s + " (Name is: " + name);
}

最適化された/パフォーマンスの低いコード:

string name = GetName(); // returned string could be empty
List<string> myListOfStrings = GetListOfStrings();

foreach(string s in myListOfStrings)
    Console.WriteLine(string.IsNullOrWhiteSpace(name) ? s : s + " (Name is: " + name);

ループごとに条件「string.IsNullOrWhiteSpace(name)」を 1 回だけ実行するため、明らかに「最初の」コードの実行時間は短くなります。一方、「2 番目の」コード (より優れています) は、反復ごとに条件を実行します。

ループ実行時間が短い場合ではなく、長いループ実行時間を考慮してください。短い場合とパフォーマンスに違いがないことはわかっています。

4

2 に答える 2

3

コンパイラは、パフォーマンスが「最初の」コードと同じくらい良好になるように、「2 番目の」コードを強化しますか?

いいえ、できません。

  1. ブール式がループの反復間で変化しないことはわかりません。コードが毎回同じ値を返さない可能性があるため、反復ごとにチェックを実行する必要があります。

  2. ブール式に副作用がある可能性もあります。この場合はそうではありませんが、コンパイラがそれを知る方法はありません。仕様を満たすためには、そのような副作用が実行されることが重要であるため、反復ごとにチェックを実行する必要があります。

では、次に質問する必要があるのは、このような場合、あなたが言及した最適化を実行することは重要ですか? どんな状況でも、あなたが示した正確なコードを想像できますが、おそらくそうではありません。チェックは非常に高速であるため、ほぼ確実にボトルネックにはなりません。パフォーマンスに問題がある場合は、ほぼ確実に大きな魚が存在します。

とはいえ、例にわずかな変更を加えるだけで、問題にすることができます。ブール式自体が計算コストが高い場合 (つまり、データベース呼び出し、Web サービス呼び出し、高価な CPU 計算などの結果である場合)、パフォーマンスの最適化が重要になる可能性があります。考慮すべきもう 1 つのケースは、ブール式に副作用がある場合にどうなるかです。MoveNextでの通話だったらIEnumerator?副作用を N 回発生させたくないために、一度だけ実行することが重要である場合、これは非常に重要な問題になります。

このような場合、いくつかの解決策が考えられます。

最も簡単な方法は、ブール式を一度計算してから変数に格納することです。

bool someValue = ComputeComplexBooleanValue();
foreach(var item in collection)
{
    if(someValue)
        doStuff(item);
    else
        doOtherStuff(item);
}

ブール値を 0 ~ 1 回実行したい場合 (つまり、コレクションが空の場合に 1 回でも呼び出さないようにする場合) Lazy、値を遅延計算するために使用できますが、計算されるのは多くても 1 回だけです。

var someValue = new Lazy<bool>(() => ComputeComplexBooleanValue());
foreach (var item in collection)
{
    if (someValue.Value)
        doStuff(item);
    else
        doOtherStuff(item);
}
于 2013-09-12T18:27:30.483 に答える
1

常に、最初に理解しやすく維持しやすい方法を使用する必要があります。これは、重複コードを絶対最小値 ( DRY ) に減らすことを意味します。さらに、この種のマイクロ最適化は、多くのシステムにとってそれほど重要ではありません。また、短いコードが常に優れているとは限らないことにも注意してください。

私はこのようなもので行くと思います:

string name = GetName(); // returned string could be empty
bool nameIsEmpty = string.IsNullOrWhiteSpace(name);

foreach (string s in GetListOfStrings()) {       

    string messageAddition = "";
    if (!nameIsEmpty) {
        messageAddition = " (Name is: " + name + ")";
    }

    Console.WriteLine(s + messageAddition);

    // more code which uses the computed value.. 
    // otherwise the condition can be moved out the loop
}

メソッド呼び出し内の演算子よりも余分なifステートメントの方が読みやすいと思います?:が、これは個人的な好みかもしれません。

後でパフォーマンスを改善したい場合は、アプリケーションのプロファイリングを行い、コードの最も遅いセクションの最適化を最初に開始する必要があります。おそらく、GetListOfStrings()メソッドが非常に遅いため、他のコードのパフォーマンスはまったく関係ありません。ループを複製することでパフォーマンスが大幅に向上することを測定した場合は、ループを変更することを検討できます。

于 2013-09-12T17:48:15.823 に答える