【问题标题】:How to queue asynchronous File IO in C#?如何在 C# 中对异步文件 IO 进行排队?
【发布时间】:2017-08-10 16:03:42
【问题描述】:

我有一个异步写入日志文件的函数,该函数被多次调用。但是,我收到一个错误:

System.IO.IOException: 'The process cannot access the file '<log path>' because it is being used by another process.'

代码在这里:

public async void log(string msg)
{
    await Task.Run(() => {

        // Check that log directory exists, or create one
        if (!Directory.Exists(@"log dir")) Directory.CreateDirectory(@"log dir");

        // Append to log
        using (StreamWriter w = File.AppendText(@"log path"))
        {
            w.WriteLine(DateTime.Now + " : " + msg);
            w.Close();
        }
    });
}

我对异步编程的理解主要来自node.js,它是一种单线程语言。我是否认为由于 C# 是多线程的(并且对异步代码采用多线程方法),所以 IO 不会像在 node.js 中那样自动排队等待资源?

有没有一种简单的方法可以在 C# 中异步写入文件?或者我最好让这个日志函数同步,因为性能成本与几行写入无关......

【问题讨论】:

  • 我的想法是触发并忘记日志行。但我想他们应该在代码中等待。在这种情况下避免碰撞
  • 你为什么不用支持异步的日志框架nuget.org/packages/Log4Net.Async

标签: c# asynchronous io


【解决方案1】:

Async Void 不好,您将无法正确捕获异常,而且通过使用同步方法运行任务,您无法获得 Async 的全部好处,您仍然会阻塞资源。

使用logging framework 可能会更好,但如果你真的想要,你可以像这样编写异步:

private async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize: 4096, useAsync: true))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    };
}

【讨论】:

  • 谢谢 - 我知道我应该使用日志框架......你的附加到文件的实现和我的有什么区别?
  • @ZachSmith 查看我的编辑,最好只使用框架来避免不可预见的问题
  • 谢谢。你添加了锁定机制吗?还是签名中的async Task?如果您等待所有异步代码,您仍然可以获得竞争条件吗?即,如果异步运行的两个独立函数将WriteTextAsync 调用到同一路径,会导致竞争吗?
  • @Nkosi,不应该认为FileShare.None 选项很好,不会像写入期间的文件
  • @johnny5 锁是这样文件写入将按照它们被调用的顺序发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-27
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
相关资源
最近更新 更多