【问题标题】:how to write to a file stream asynchronously using async/await from multiple threads in a thread-safe manner如何以线程安全的方式使用来自多个线程的 async/await 异步写入文件流
【发布时间】:2014-08-05 03:54:02
【问题描述】:

我有一个非常简单的日志实用程序,目前是同步的。它从 UI (WPF) 和线程池线程 (Task.Run) 调用,并使用 lock(_stream){_stream.WriteLine(message);} 来保证线程安全。我想添加一个异步写入方法,但不知道如何使它成为线程安全的。

  1. 以下异步方法是否有效?
  2. 它与现有的同步方法能否很好地配合使用,它们是否可以毫无问题地一起使用?
  3. 假设前面的问题已解决,最后的 Debug.WriteLine 应该进入 try 块内还是位于当前所在的 finally 之后 - 有什么不同吗?
private static SemaphoreSlim _sync = new SemaphoreSlim(1);    

public static async Task WriteLineAsync(string message)
{
    if (_stream != null)
    {
        await _sync.WaitAsync();

        try
        {
            await _stream.WriteLineAsync(string.Format("{0} {1}", DateTime.Now.ToString("HH:mm:ss.fff") + message));
        }
        catch(Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
        finally
        {
            _sync.Release();
        }

        Debug.WriteLine("{0} {1}", DateTime.Now.ToString("HH:mm:ss.fff"), message);
    }
}

【问题讨论】:

  • 试试BlockingCollection<T>,它有很多内置功能可以开箱即用。
  • 您不应该使用信号量来实现互斥。计数为 1 的信号量与互斥原语(例如 lock)之间存在显着差异。在这里使用lock 而不是信号量。如果您认为合适,请使用SpinLock
  • @JimMischel 我不明白。您不能在lock 内部使用await。那么你将如何异步lock
  • 你是对的。我以为MonitorSpinLock 上有一个TryEnterAsync

标签: c# .net multithreading asynchronous async-await


【解决方案1】:

下面的异步方法会起作用吗?

如果流设置正确,那么是的,我看不出它为什么不这样做的原因

它会与现有的同步方法一起使用吗?它们可以毫无问题地一起使用吗?

如果您的同步方法使用相同的SemaphoreSlim 并使用同步Wait,它们应该可以很好地配合。

假设前面已经解决,最终的 Debug.WriteLine 应该进入 try 块内部还是在 finally 之后它当前所在的位置 - 有什么不同吗?

如果当且仅当流成功将消息写入流时才应该写入调试消息,它应该在您的 try 块内,在调用 WriteLineAsync 之后。

【讨论】:

  • 如果应该写入调试消息,无论流写入是否成功,并且与写入流的消息顺序相同(如果有),那么它应该进入@987654325 @block,在调用WriteLineAsync之前。 (我在这里假设Debug.WriteLine 不会失败。)
  • 看来SemaphoreSlim 没有WaitOne() 方法。也许Wait() 是等价的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-16
  • 2012-09-24
  • 1970-01-01
  • 2021-11-06
相关资源
最近更新 更多