1

弦のパフォーマンスに関する質問はいくらでもありますが、最適なアプローチが何であるかについてはまだ頭も尻尾もわかりません。

簡単に言うと、私は 4NT から PowerShell に移行することを約束しました。4NT を離れると、FFIND と呼ばれるコンソールの超高速文字列検索ユーティリティが恋しくなります。初歩的な C# プログラミング スキルを使用して、PowerShell で使用する独自のユーティリティを作成することにしました。

これまでのところ、いくつかの 1000 個のファイルにまたがる数百個のディレクトリでの文字列検索の検索結果は、非常に大きいものもあり、FFIND 2.4 秒であり、私のユーティリティは 4.4 秒です。 ?

初めてFFINDを実行したときはほぼ同時に実行されますが、私の場合は1分以上かかりますか? これは何ですか?ライブラリのロード?ファイルの索引付け? コードで何か間違ったことをしていますか? もう少し待つことは気にしませんが、違いは非常に大きいので、より良い言語やアプローチがあれば、投資しすぎる前に今すぐその道を歩み始めたいと思います.

高速な文字列検索を作成するには、別の言語を選択する必要がありますか?

このユーティリティを使用して、1000 個のファイルから Web コード、C# コード、およびテキスト ファイルを使用する別の固有言語の文字列を検索する必要があります。また、このユーティリティを使用して、非常に大きなログ ファイル (MB サイズ) 内の文字列を検索できるようにする必要もあります。

class Program
{
    public static int linecounter;
    public static int filecounter;
    static void Main(string[] args)
    {
        //
        //INIT
        //
        filecounter = 0;
        linecounter = 0;
        string word;
        // Read properties from application settings.
        string filelocation = Properties.Settings.Default.FavOne;
        // Set Args from console.
        word = args[0];
        //
        //Recursive search for sub folders and files
        //
        string startDIR;
        string filename;
        startDIR = Environment.CurrentDirectory;
        //startDIR = "c:\\SearchStringTestDIR\\";
        filename = args[1];
        DirSearch(startDIR, word, filename);

        Console.WriteLine(filecounter + " " + "Files found");
        Console.WriteLine(linecounter + " " + "Lines found");
        Console.ReadKey();
    }

    static void DirSearch(string dir, string word, string filename)
    {
        string fileline;
        string ColorOne = Properties.Settings.Default.ColorOne;
        string ColorTwo = Properties.Settings.Default.ColorTwo;
        ConsoleColor valuecolorone = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorOne);
        ConsoleColor valuecolortwo = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorTwo);

        try
        {
            foreach (string f in Directory.GetFiles(dir, filename))
            {
                StreamReader file = new StreamReader(f);
                bool t = true;
                int counter = 1;
                while ((fileline = file.ReadLine()) != null)
                {
                    if (fileline.Contains(word))
                    {
                        if (t)
                        {
                        t = false;
                        filecounter++;
                        Console.ForegroundColor = valuecolorone;
                        Console.WriteLine(" ");
                        Console.WriteLine(f);
                        Console.ForegroundColor = valuecolortwo;
                        }
                        linecounter++;
                        Console.WriteLine(counter.ToString() + ". " + fileline);
                    }
                    counter++;
                }
                file.Close();
                file = null;
            }
            foreach (string d in Directory.GetDirectories(dir))
            {
                //Console.WriteLine(d);
                DirSearch(d,word,filename);
            }

        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
}
4

1 に答える 1

1

コードを高速化したい場合は、パフォーマンス分析を実行して、何が最も時間がかかっているかを確認してください。ここでの最長のステップはほぼ保証できます

fileline.Contains(word)

この関数は、ファイルのすべての行で、すべてのファイルで呼び出されます。文字列内の単語を単純に検索すると、len(string) * len(word) の比較が行われます。

より高速な文字列比較アルゴリズムを使用する独自の Contains メソッドをコーディングできます。「高速文字列完全一致」の Google。正規表現を使用して、パフォーマンスが向上するかどうかを確認できます。しかし、あなたが試すことができる最も簡単な最適化は次のとおりだと思います:

すべての行を読まないでください。ファイルのすべてのコンテンツの大きな文字列を作成します。

StreamReader streamReader = new StreamReader(filePath, Encoding.UTF8);
string text = streamReader.ReadToEnd();

これに含まれるものを実行します。

ファイル内のすべての一致が必要な場合は、Regex.Matches(string,string) のようなものを使用する必要があります。

正規表現を使用して 1 つのファイルのすべての一致を取得したら、この一致コレクションを反復処理できます (一致するものがあれば)。一致するたびに、一致オブジェクトのインデックス属性から「\n」文字が見つかる場所まで前後に読み取る関数を作成することにより、元のファイルの行を復元できます。次に、これらの 2 つの改行の間にその文字列を出力して、行を取得します。

これははるかに高速になります、私はそれを保証します。

さらに先に進みたい場合は、次のことに気付きました。

ループの外側から try catch ステートメントを削除します。必要な場所だけに使用してください。私はそれをまったく使用しません。

また、システムが実行されていることを確認してください、ngen. ほとんどのセットアップには通常これがありますが、ngen が実行されていないことがあります。プロセス エクスプローラーでプロセスを確認できます。Ngen は C# マネージ バイトコードのネイティブ イメージを生成するため、コードを毎回解釈する必要はなく、ネイティブに実行できます。これにより、C# が大幅に高速化されます。

編集

その他のポイント: 初回実行時間と 2 回目実行時間に違いがあるのはなぜですか? キャッシングのようです。OS は、ディレクトリ、ファイル、プログラムの実行とロードに対する要求をキャッシュできた可能性があります。通常、最初の実行後にスピードアップが見られます。ここでも Ngen が役割を果たしている可能性があります。最初の実行でのコンパイル後にネイティブ イメージを生成し、それをネイティブ イメージ キャッシュに保存することです。

一般的に、C# のパフォーマンスは好みに合わせて変動しすぎます。提案された最適化が満足のいくものではなく、より一貫したパフォーマンス結果が必要な場合は、別の言語 (「管理されていない」言語) を試してください。C はおそらくあなたのニーズに最適です。

于 2012-12-20T01:31:37.093 に答える