我如何更新我的API使用async关键字,而不使用等待所有调用者



我正在尝试将一些TcpClient依赖的代码移植到。net 4.5,使用StreamSocketDataReader代替。

我有一个名为ReadLine()的函数,它在任何地方使用。通过在代码体(LoadAsync())中使用DataReader,我的方法被强制标记为async关键字。

链式反应如下:现在我有数百个地方,我必须将async添加到调用方法中,并将await应用于底层async方法调用。

这就引出了我的下一个问题……是否有一种简单的方法来包装ReadLine(),使调用方法不知道它是一个异步方法,这样我就不必改变我的代码的其余部分?

也……我经常在多个地方的循环中使用这个方法调用。如果这些方法现在被标记为async,我担心我可能会在我不应该的时候从流中读取数据,这将导致各种噩梦。这是个问题还是我想得太超前了?

也……我经常在多个地方的循环中使用这个方法调用。如果这些方法现在被标记为异步,我担心我可能会在不应该从流中读取数据的时候读取数据,这将导致各种各样的噩梦。这是个问题还是我想得太超前了?

如果你总是在调用*Async方法时使用await,那么你的async方法就会像同步方法一样(除了它们不会阻塞)。因此,在循环中使用await将像您期望的那样工作。


async确实通过代码库"增长"。我通常认为这类似于"海龟一路向下"的古老故事;还有人称它为"僵尸病毒"。

我在我的博客上详细描述了死锁的情况。正如我在那里所说的,最好的选择是允许async增长。 如果必须为异步方法创建同步包装器,请参阅Stephen Toub的建议。您可以使用Task.Result,但是您需要做两件事:
  • 所有地方都使用ConfigureAwait(false)。这将避免死锁的情况。
  • 请注意Result有不同的错误处理语义。

对于您的特定示例,像这样的内容应该足够了:

private async Task<string> ReadLineAsync()
{
  ... // *Every* await in this method and every method it calls
      // must make use of ConfigureAwait(false).
}
public string ReadLine()
{
  try
  {
    return ReadLineAsync().Result;
  }
  catch (AggregateException ex)
  {
    ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
    throw;
  }
}

在选择混合同步/异步代码库之前,请仔细考虑复杂性。这并不像看上去那么容易。

注:一般来说,TCP/IP代码应该都是异步的。在套接字上进行连续的异步读取通常是个好主意。

创建一个ReadLineAsync函数和一个ReadLine函数
在ReadLine函数中,你可以像这样调用ReadLineAsync:

var readLineTask = ReadLineAsync(); 
readLineTask.Wait() 

标记为async并不意味着无论何时调用它都必须等待。你将其标记为异步,因为你在方法中使用了await。

这意味着你不必因为在那里调用ReadLine()而将其他方法标记为async。

如果你的readline方法是可等待的,它必须返回TaskTask<T>

相关内容

  • 没有找到相关文章

最新更新