1

次のコードがあります。複数のスレッドでファイルの作成を開始したいと考えています。目的は、複数のスレッドで実行するときに 10 個のファイルを作成するのにかかる時間を短縮することです。私が理解しているように、それを実現するには非同期呼び出しの要素を導入する必要があります。

このコードにどのような変更を加える必要がありますか?

using System;
using System.Text;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace MultiDemo
{
    class MultiDemo
    {
        public static void Main()
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
            // Create an instance of the test class.
            var ad = new MultiDemo();

            //Should create 10 files in a loop.
            for (var x = 0; x < 10; x++)
            {
                var y = x;
                int threadId;
                var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
                myThread.Start();
                myThread.Join();
                //TestMethod("outpFile", y, out threadId);
            }
            stopWatch.Stop();
            Console.WriteLine("Seconds Taken:\t{0}",stopWatch.Elapsed.TotalMilliseconds);
        }

        public static void TestMethod(string fileName, int hifi, out int threadId)
        {
            fileName = fileName + hifi;
            var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            var sw = new StreamWriter(fs, Encoding.UTF8);
            for (int x = 0; x < 10000; x++)
                {
                    sw.WriteLine(DateTime.Now.ToString());
                }
            sw.Close();
           threadId = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("{0}",threadId);
        }
    }
}

現時点では、コードのスレッド作成部分にコメントを付けて、ループ内で testMethod を 10 回呼び出すだけで、スレッド作成が処理しようとする複数のスレッドよりも高速です。

4

8 に答える 8

5

コードのスレッド化されたバージョンは余分な作業を行っているため、遅くなっても驚くことではありません。

次のようなことをすると:

var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
myThread.Start();
myThread.Join();

...スレッドを作成し、それを呼び出してTestMethod、それが終了するのを待っています。 スレッドを作成して開始する追加のオーバーヘッドにより、スレッドTestMethodなしで単に呼び出すよりも処理が遅くなります。

すべてのスレッドの動作を開始してから、それらが終了するのを待つと、パフォーマンスが向上する可能性があります。次に例を示します。

var workers = new List<Thread>();
for (int i = 0; i < 10; ++i) 
{
   var y = x;
   int threadId;
   var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
   myThread.Start();
   workers.Add(myThread);
}
foreach (var worker in workers) worker.Join();
于 2012-07-03T19:55:01.800 に答える
1

あなたのケースで最初に守るべきことは、アムダールの法則です。あなたのアルゴリズムは、次の各リソースをほぼ均等に使用します。

  1. プロセッサー使用率
  2. メモリアクセス
  3. ドライブへのアクセス

これらのうち、ドライブ アクセスは最も遅い項目であるため、高速化を確認するには、このリソース全体でアルゴリズムを並列化する必要があります。つまり、10 個の異なるファイルを 10 個の異なるドライブに書き込んでプログラムを並列化すると、ファイルの内容の計算を並列化するだけの場合に比べて、パフォーマンスが大幅に向上します。実際、10 個の異なるスレッドでファイルを作成すると、ドライブ アクセスに関連するシリアル化により、プログラムの全体的なパフォーマンスが実際に低下する可能性があります。

どちらもマルチスレッド プログラミングを意味しますが、IO の場合、並列化を非同期プログラミングと同じように扱うべきではありません。ファイル システムの使用を並列化することはお勧めしませんが、ファイルの読み取り/書き込みに非同期メソッドを使用することは、ほとんどの場合有益です。

于 2012-07-03T20:07:02.450 に答える
1

おそらくこれはあなたの質問に直接答えるものではありませんが、これが私の考えです。そのコードのボトルネックがプロセッサである可能性は低いです。ディスク IO は、CPU 処理よりもはるかに時間がかかると思います。そのため、新しいスレッドの作成がまったく役立つとは思いません (すべてのスレッドが同じディスクに書き込もうとします)。これは時期尚早の最適化のケースだと思います。私があなたなら、すべてを 1 つのスレッドで実行します。

于 2012-07-03T19:49:11.143 に答える
1

あなたが遅い理由は、あなたがしているのは新しいスレッドを開始してそれが完了するのを待っているだけだからです。他の方法は単に3つのステップを実行していないため、遅くする必要があります.

これを試してみてください (TPL のために .Net 4.0 を想定しています)。私のマシンでは、並行して実行すると、一貫して 100 ミリ秒高速になります。

[Test]
public void Y()
{
    var sw = Stopwatch.StartNew();
    Parallel.For(0, 10, n => TestMethod("parallel", n));

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);

    sw.Restart();

    for (int i = 0; i < 10; i++)
        TestMethod("forloop", i);

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}


private static void TestMethod(string fileName, int hifi)
{
    fileName = fileName + hifi;
    var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    var sw = new StreamWriter(fs, Encoding.UTF8);
    for (int x = 0; x < 10000; x++)
    {
        sw.WriteLine(DateTime.Now.ToString());
    }
    sw.Close();
}
于 2012-07-03T19:55:24.247 に答える
0

速度を上げるのは間違った方法であり、並列作業ではマルチスレッド化されますが、加速するためではありません

于 2012-07-03T19:43:33.000 に答える
0

次のようなものを試してください:

for (int i = 0; i < 10; ++i)  
{ 
   new Action(() => { TestMethod("outpFile"); }).BeginInvoke(null,null); 
}
Console.ReadLine();

シリアルコールよりも速くならない場合、実際にIOがボトルネックであり、それについて何もできません。

于 2012-07-03T20:21:09.873 に答える
0

では、なぜマルチスレッドを使用することにしたのですか? 新しいスレッドを開始するコストは、単純なループよりも高くなる可能性があります。盲目的に決定できるものではありません...スレッドの使用を主張する場合は、既存のスレッドを再利用することにより、新しいスレッドを作成するコストを削減できるマネージドThreadPool / async delegatesの使用を確認することもできます。

于 2012-07-03T19:50:32.453 に答える
0

Join各スレッドを作成し、次のスレッドを作成して開始する前にスレッドが完了するのを待つため、複数のスレッドの利点を無効にしています。

代わりに、スレッドを作成して開始するときにスレッドをリストに追加し、スレッドのリストをループして、終了するまで順番に結合します。

using System.Collections.Generic;
List<Thread> threads= new List<Thread>();
//Should create 10 files in a loop.
for (var x = 0; x < 10; x++)
{
    var y = x;
    int threadId;
    var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
    threads.Add(myThread);
    myThread.Start();
    //myThread.Join();
    //TestMethod("outpFile", y, out threadId);
}
foreach (var thread in threads) thread.Join();
于 2012-07-03T19:55:15.477 に答える