3

パフォーマンスに関する質問があります。

大きなテキスト ファイル (請求書) を解析し、特定のテキストが請求書に表示されるかどうかに基づいて、サービス プロバイダーの名前を変数に割り当てています。

これは、私が行っていたことの小さなサンプルです (笑わないでください。面倒なことはわかっています)。全部で約 250 の if、else if があります。

if (txtvar.BillText.IndexOf("SWGAS.COM") > -1)
   {
       txtvar.Provider = "Southwest Gas";
   }
else if (txtvar.BillText.IndexOf("georgiapower.com") > -1)
   {
       txtvar.Provider = "Georgia Power";
   }
else if (txtvar.BillText.IndexOf("City of Austin") > -1)
   {
       txtvar.Provider = "City of Austin";
   }

// など 250 回

それが非常に大きくなったので、よりクリーンで効率的にするために別のアプローチを取ることにしました。最終的に、外部の .psv ファイルに保存するマッピングを実装しました。

そのマッピングを変数に保存します (これは 1 回だけ実行され、約 35 ミリ秒かかります...

var providerMap =
                    System.IO.File.ReadLines(@"U:\Program\ApplicationFiles\ProvidersList.psv")
                    .Select(line => line.Split('|'))
                    .Select(parts => new Provider() { Pattern = parts[0], Name = parts[1] }).ToList();

...そして、各請求書をループします (プロバイダーの割り当てには約 2 ミリ秒かかりますが、if ステートメントの所要時間は半分以下です....

foreach (string bills in files)
                                {
                                    string Provider = providerMap.First(p => txtvar.BillText.IndexOf(p.Pattern) > -1).Name;
                                    OtherStuff();
                                }

このソリューションははるかにクリーンですが、驚くべきことに、250 以上の if、else if よりもはるかに低速です。ストップウォッチ メソッドを使用して、よりクリーンなメソッドが実際には数百の if ステートメントの 2 倍遅いことを確認しました。(ifステートメントの最初と最後にある請求書をテストし、同様の結果でマッピングしました)

誰か私にこれを説明できますか?多分私は何か間違ったことをしていますか?ありがとう!

4

3 に答える 3

1

ループ展開は、ループを一連のステートメントに変換することでパフォーマンスを向上させる手法です。些細な例

for(int i = 0; i < 3; i++)
{
    Console.WriteLine(i);
}

に展開できます

Console.WriteLine(0);
Console.WriteLine(1);
Console.WriteLine(2);

これにはさまざまな高度なテクニックがありますが、ポイントは、ループ変数のインクリメント、条件の評価、およびマシン コードのジャンプ命令の数を減らすことです。この手法は、常にパフォーマンスを向上させるとは限らないことに注意してください。詳細な説明と例については、ループの巻き戻しを参照してください。

あなたは別の道を歩んできました。あなたは非常に長いif-else構造を取り、それを次のように変えました

string Provider = providerMap.First(p => txtvar.BillText.IndexOf(p.Pattern) > -1).Name;

これですべてFirstが効果的に実行されます(Firstアイテムが一致しない場合にスローされることに注意してください):

Provider found = null;
foreach(var provider in providerMap)
{
    if (txtvar.BillText.IndexOf(provider.Pattern) > -1)
    {
        found = provider;
        break;
    }
}

つまり、一連のステートメントからループへと逆になっていることがわかります。

コードを再コンパイルせずにプロバイダーを追加できるという、言及していない何かを得たと思います。これは便利な場合があります。

于 2013-09-24T17:51:59.903 に答える
0

私は 3 番目のオプションを使用します。

1-読みやすい

2-少ないコード、これもパフォーマンス +1 になります。

3-メンテナンスがより簡単

4- dll 内に文字列がないため、dll のサイズも小さくなります

于 2013-09-24T15:46:57.617 に答える