4

テキストファイルに書き込むメソッドが与えられた場合

public void WriteToFile( ) {
    var file = "C:\\AsyncTest.txt";
    var writer = File.Exists( file ) ? File.AppendText( file ) : File.CreateText( file );
    writer.WriteLine( "A simulated entry" );
    writer.Close();
}

このメソッドがループ内で (おそらく数十回) 呼び出される可能性があり、非同期で実行する必要があるシナリオをシミュレートする必要があります。

だから私はそのように新しいスレッドでメソッドを呼び出してみました(ライターはWriteToFileが存在するクラスです)

//in a loop...
  Thread thread = new Thread( writer.WriteToFile );
  thread.Start(  );

これは一度完全に機能しますが、ファイルが後続の反復で別のプロセスによって使用されているという IO 例外をスローします。実際、これは完全に理にかなっていますが、それを回避する方法がわかりません。

このように Join() を使用してみました

Thread thread = new Thread( writer.WriteToFile );
thread.Start(  );
thread.Join();

しかし、それは結合されたすべてのスレッドが完了するまで呼び出し元のスレッドをロックします。

を使用してみThreadPool.QueueUserWorkItem(writer.WriteToFile);ましたが、同じ IO 例外が発生します。

ロックを使ってみた

private object locker = new object();

public void WriteToFile( ) {
  lock(locker){
    //same code as above
  }
}

しかし、それは明らかな効果がありませんでした

また、 Task クラスを使用してみましたが、役に立ちませんでした。

では、これらのバックグラウンド スレッドを「スタック」して、呼び出し元のスレッドをロックせずに、競合することなく単一のファイルに書き込むにはどうすればよいでしょうか?

4

4 に答える 4

11

もう 1 つのオプションは、キューを作成することです。メイン スレッドに文字列をキューに入れさせ、永続的なバックグラウンド スレッドにキューを読み取らせてファイルに書き込むようにします。やり方はとても簡単です。

private BlockingCollection<string> OutputQueue = new BlockingCollection<string>();

void SomeMethod()
{
    var outputTask = Task.Factory.StartNew(() => WriteOutput(outputFilename),
        TaskCreationOptions.LongRunning);

    OutputQueue.Add("A simulated entry");
    OutputQueue.Add("more stuff");

    // when the program is done,
    // set the queue as complete so the task can exit
    OutputQueue.CompleteAdding();

    // and wait for the task to finish
    outputTask.Wait();
}

void WriteOutput(string fname)
{
    using (var strm = File.AppendText(filename))
    {
        foreach (var s in OutputQueue.GetConsumingEnumerable())
        {
            strm.WriteLine(s);
            // if you want to make sure it's written to disk immediately,
            // call Flush. This will slow performance, however.
            strm.Flush();
        }
    }
}

バックグラウンド スレッドは出力キューで非ビジー待機を行うため、実際にデータを出力するとき以外は CPU リソースを使用しません。また、他のスレッドは何かをキューに入れる必要があるだけなので、基本的に待機はありません。

詳細については、私のブログ、Simple Multithreading、パート 2を参照してください。

于 2013-08-01T13:56:28.717 に答える