在后台写入文件

For*_*Two 4 .net c# io

给定一种写入文本文件的方法

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();
}
Run Code Online (Sandbox Code Playgroud)

我需要模拟一个场景,在这个场景中,可以在循环中调用此方法,可能需要几十次,并且必须异步运行.

所以我尝试在一个新的线程中调用该方法(其中writer是WriteToFile所在的类)

//in a loop...
  Thread thread = new Thread( writer.WriteToFile );
  thread.Start(  );
Run Code Online (Sandbox Code Playgroud)

哪个工作完美一次,但抛出了一个IO异常,即在后续迭代中另一个进程正在使用该文件.实际上,这很有道理,但我不知道如何解决它.

我试过像这样使用Join()

Thread thread = new Thread( writer.WriteToFile );
thread.Start(  );
thread.Join();
Run Code Online (Sandbox Code Playgroud)

但是这会锁定调用线程,直到所有连接的线程都完成,哪种方式会破坏目的,不是吗?

我尝试使用ThreadPool.QueueUserWorkItem(writer.WriteToFile);,但得到相同的IO异常.

我试过用锁

private object locker = new object();

public void WriteToFile( ) {
  lock(locker){
    //same code as above
  }
}
Run Code Online (Sandbox Code Playgroud)

但这没有明显的效果

我也试过使用Task类无济于事.

那么如何在不冲突的情况下"堆叠"这些后台线程来写入单个文件,而不是锁定调用线程?

Jim*_*hel 11

另一种选择是创建队列.让主线程将字符串放在队列中,并让持久的后台线程读取队列并写入文件.这很容易做到.

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

后台线程在输出队列上执行非繁忙等待,因此它不使用CPU资源,除非它实际输出数据.而且因为其他线程只需要在队列中放置一些东西,所以基本上没有等待.

有关更多信息,请参阅我的博客,简单多线程,第2部分.