c# - 在后台写入文件

标签 c# .net 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();
}

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

所以我尝试像这样在一个新线程中调用该方法(writer 是 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 类,但无济于事。

那么我怎样才能“堆叠”这些后台线程以在不发生冲突的情况下写入单个文件,同时又不锁定调用线程?

最佳答案

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

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, Part 2了解更多信息。

关于c# - 在后台写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17994169/

相关文章:

c# - EmguCV 3.0 中缺少 Image<TColor, TDepth>.FindContours

c# - 是否有打开 resharper 菜单的快捷方式?

c# - 在 .NET 中序列化高度链接的数据(自定义 JSON.NET 引用)

c# - 如何将不同的类库编译成一个 dll?

c# - 如何使用反射创建 C# 数组并仅输入信息?

.net - JSON 序列化 - 删除空键

.net - [Bind(Exclude = "AlbumId")]注解在数据验证中的作用是什么?脚手架是什么意思?

python - 在python项目中使用相对路径读取文件

java - 尝试删除文件时出现 AccessControlException

java - 今天我们真的需要在 close() 之前调用 flush() 吗?