1

私は次の2つの方法を使用しています。DoMyWork1 と呼ばれるメソッドは、3 つのスレッドで 3 つのメソッドを実行するのに 6 秒かかるなど、適切にスケーリングします。一方、DoMyJob メソッドはまったくスケーリングしません。1 つのスレッドに 4 秒かかる場合、3 つのスレッドを実行するには 13 秒かかります。私は何を間違っていますか?ファイルの読み取りおよび/または書き込みには、スレッド プール以外の特別なスレッド処理が必要ですか?

私の呼び出しコード

public static void Process(MyDelegate md , int threads)
{
    int threadcount = threads;

    ManualResetEvent[] doneEvents = new ManualResetEvent[threadcount];

    DateTime dtstart = DateTime.Now;

    List<string> myfiles = GetMyFiles(@"c:\");


    for (int i = 0; i < threadcount; i++)
    {

        doneEvents[i] = new ManualResetEvent(false);
        MyState ms = new MyState();
        ms.ThreadIndex = i;
        ms.EventDone = doneEvents[i];
        ms.files = myfiles;
        ThreadPool.QueueUserWorkItem(md.Invoke, ms);
    }


    WaitHandle.WaitAll(doneEvents);

    DateTime dtend = DateTime.Now;
    TimeSpan ts = dtend - dtstart;
    Console.WriteLine("All complete in {0} seconds.", ts.ToString());
    Console.ReadLine();

}

public static void DoMyWork1(Object threadContext)
{
    MyState st = (MyState)threadContext;
    Console.WriteLine("thread {0} started...", st.ThreadIndex);

    Thread.Sleep(5000);

    Console.WriteLine("thread {0} finished...", st.ThreadIndex);
    st.EventDone.Set();
}



private static void DoMyJob(MyState st)
{
    Console.WriteLine("I am in thread {0} started...", st.ThreadIndex);


    string[] mystrings = new string[] { "one", "two", "three" };

    foreach (string s in mystrings)
    {
        foreach (string file in st.files)
        {
            if (!(new StreamReader(file).ReadToEnd().Contains(s)))
            {
                AppendToFile(String.Format("{0} word searching in file {1} in thread {2}", s, file, st.ThreadIndex));
            }


        }
    }

    Console.WriteLine("I am in thread {0} ended...", st.ThreadIndex);
}
4

4 に答える 4

2

スレッドは、プログラムの CPU リソースが不足している場合にのみ、プログラムのパフォーマンスを向上させることができます。これは、プログラムには当てはまりません。Taskmgr.exe の [パフォーマンス] タブからすぐに確認できるはずです。ここで遅いリソースは、ハードディスクまたはネットワーク カードです。ReadToEnd() 呼び出しは非常に遅く、ディスクがファイル データを取得するのを待っています。ファイル データに対して行うその他の処理は、それよりも 3 桁も簡単に高速化されます。

スレッドは、ディスク データを順番に待つだけです。実際、スレッドが実際にプログラムの実行を大幅に遅くする可能性は十分にあります。各スレッドは異なるファイルを処理しているため、ディスク ドライブのヘッドがディスク上のばらばらなトラック間を行ったり来たりします。本当に遅いのは、ヘッドが別のトラックをシークすることです。通常、高速ディスクの場合は約 10 ミリ秒です。約 50 万の CPU 命令に相当します。

より高速なディスクを入手しない限り、プログラムを高速に実行することはできません。SSDはいいですね。ファイル システム キャッシュの影響に注意してください。プログラムを 2 回目に実行すると、ファイル データがディスクではなくキャッシュから取得されるため、非常に高速に実行されます。これは、本番環境ではめったに発生しません。

于 2009-12-13T12:10:54.527 に答える
0

すべてのファイル アクセスは OS レイヤーでシリアルになり、そのようにスレッド化すると、まさに表示どおりになります。

于 2009-12-13T04:47:24.413 に答える
0

私は少し驚いています。これらのファイルへの最初のアクセスはキャッシュされ、残りのアクセスはメモリにヒットするだけだと思います。したがって、3 つのスレッドが 1 つよりも遅くなりすぎてはなりません。各ファイルに書き込んでいる場合、それは違いを生むでしょう - AppendToFile 関数は正確に何をしますか?

于 2009-12-13T05:30:21.190 に答える
0

問題の 1 つは、探している新しい文字列ごとに、各ファイルを開いて読み取ることです。

foreach ループの順序を入れ替えて、必要なときにのみファイルに追加するとどうなるでしょうか?

より良いパフォーマンスが見られると思います。

理想的には、ファイルの読み取りをループから完全に取り除くことができれば、それが最速になります。I/O バウンド操作では常に、コンテキスト スイッチがディスク上でデータを返すのを待機します。

于 2009-12-13T05:40:52.740 に答える