4

私はこのコードを持っています:

var options = GetOptions(From, Value, SelectedValue);     
var stopWatch = System.Diagnostics.Stopwatch.StartNew();

foreach (Option option in options)
{
    stringBuilder.Append("<option");

    stringBuilder.Append(" value=\"");
    stringBuilder.Append(option.Value);
    stringBuilder.Append("\"");

    if (option.Selected)
        stringBuilder.Append(" selected=\"selected\"");

    stringBuilder.Append('>');

    stringBuilder.Append(option.Text);
    stringBuilder.Append("</option>");
}

HttpContext.Current.Response.Write("<b>" + stopWatch.Elapsed.ToString() + "</b><br>");

最初の試行で 00:00: 00.0004255
(デバッグではありません)
00:00:00.0004260 を 2 回目の試行で、
00:00:00.0004281 を 3 回目の試行で書き込みます。

ここで、メジャーがforeach ループになるようにコードを変更すると、次のようになります。

var options = GetOptions(From, Value, SelectedValue);     

foreach (Option option in options)
{
    var stopWatch = System.Diagnostics.Stopwatch.StartNew();

    stringBuilder.Append("<option");

    stringBuilder.Append(" value=\"");
    stringBuilder.Append(option.Value);
    stringBuilder.Append("\"");

    if (option.Selected)
        stringBuilder.Append(" selected=\"selected\"");

    stringBuilder.Append('>');

    stringBuilder.Append(option.Text);
    stringBuilder.Append("</option>");

    HttpContext.Current.Response.Write("<b>" + stopWatch.Elapsed.ToString() + "</b><br>");
}

...
最初の試行で [00:00:00.0000014, 00:00:00.0000011] = 00:00:00.0000025 を取得します (デバッグではありません),
[00:00:00.0000016, 00:00:00.0000011] = 00: 2 回目の試行では 00:00.0000027 となり、3 回目の試行では
[00:00:00.0000013, 00:00:00.0000011] = 00:00:00.0000024 となります。

?!
最初の結果からすればまったくナンセンスです... ループが遅いとは聞いていましたが、こんなにforeach遅いとは想像もしていませんでした... そうですか。

optionsには 2 つのオプションがあります。option必要に応じて、クラスを次に示します。

public class Option
{
    public Option(string text, string value, bool selected)
    {
        Text = text;
        Value = value;
        Selected = selected;
    }

    public string Text
    {
        get;
        set;
    }

    public string Value
    {
        get;
        set;
    }

    public bool Selected
    {
        get;
        set;
    }
}

ありがとう。

4

4 に答える 4

9

foreach ループ自体は時間差とは関係ありません。

GetOptions メソッドは何を返しますか? 私の推測では、オプションのコレクションを返すのではなく、オプションを取得できる列挙子を返しています。つまり、オプションの実際のフェッチは、反復処理を開始するまで行われません。

最初のケースでは、オプションの繰り返しを開始する前にクロックを開始しています。つまり、オプションをフェッチする時間が時間に含まれています。

2 番目のケースでは、オプションの繰り返しを開始した後にクロックを開始しています。つまり、オプションを取得する時間は時間に含まれていません

つまり、foreach ループ自体が原因ではなく、オプションを取得するのにかかる時間です。

オプションをコレクションに読み込むことで、オプションがすぐに取得されるようにすることができます。

var options = GetOptions(From, Value, SelectedValue).ToList();

ここでパフォーマンスを測定すると、ほとんど違いが見られません。

于 2009-12-13T16:33:54.457 に答える
1

何かを行うのにかかる時間を 160 回測定すると、通常、1 回の時間を測定するよりも 160 倍の時間がかかります。ループの内容が 1 回だけ実行されることを示唆していますか、それともチョークとチーズを比較しようとしていますか?

最初のケースでは、コードの最後の行を stopWatch.Elapsed.ToString() の使用から stopWatch.Elapsed.ToString() / options.Count に変更してみてください。

これは、少なくとも 1 つの反復と 1 つの反復を比較していることを意味します。

ただし、結果はまだ役に立たないでしょう。非常に短い操作を 1 回計ると、結果は悪くなります。統計的に意味のある平均時間を得るには、このようなことを何万回も繰り返さなければなりません。そうしないと、システム クロックの不正確さと、タイマーの開始と停止に伴うオーバーヘッドにより、結果が圧倒されます。

また、これらすべてが発生している間、PC は何をしているのでしょうか。CPU をロードしている他のプロセスがある場合、それらは簡単にタイミングに干渉する可能性があります。ビジーなサーバーでこれを実行している場合、完全にランダムな結果が得られる可能性があります。

最後に、テストの実行方法によって状況が変わる可能性があります。常にテスト 1 の後にテスト 2 を実行すると、最初のテストの実行が CPU キャッシュ (オプション リスト内のデータなど) などに影響を与え、次のコードをより高速に実行できるようになる可能性があります。テスト中にガベージ コレクションが発生すると、結果が歪められます。

比較する価値のある数値を得る前に、これらすべての要因を排除する必要があります。その場合にのみ、「テスト 1 の実行がテスト 2 よりもずっと遅いのはなぜですか」と尋ねる必要があります。

于 2009-12-13T16:20:22.227 に答える
0

最初のコード例は、すべてのオプションが繰り返されるまで何も出力しませんが、2 番目のコード例は、最初のオプションが処理された後の時間を出力します。複数のオプションがある場合、このような違いが見られると予想されます。

于 2009-12-13T15:29:51.077 に答える
0

IDE で数回一時停止するだけで、時間がどこに行くかがわかります。

物事にかかる時間はコードの量に比例すると考える非常に自然で強い誘惑があります。たとえば、どちらが速いと思いますか?

for (MyClass x in y)

for (MyClass theParticularInstanceOfClass in MyCollectionOfInstances)

実際にはコードサイズは無関係であり、多くの高価な操作を隠している可能性がある場合、最初の方が高速であると考えるのは当然です。

于 2009-12-13T20:47:16.167 に答える