5

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

我有一个名为的函数ReadLine(),它无处不在。通过DataReader在这段代码的主体(LoadAsync())中使用,我的方法被迫用async关键字标记。

连锁反应如下:现在我有数百个地方必须添加async到调用方法并将等待应用于底层async方法调用。

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

另外...我经常从多个地方循环使用此方法调用。如果现在标记了这些方法async,恐怕我可能会在不应该的时候从流中读取数据,这将导致各种噩梦。这是一个问题还是我想得太远了?

4

3 回答 3

8

Also... I often use this method call in a loop, from multiple places. If these methods are now marked async, i'm afraid I might be reading data off a stream when I shouldn't be, which will cause all sorts of nightmares. Is it a problem or am I thinking too far ahead?

If you always use await whenver you call *Async methods, then your async methods will act just like synchronous methods (except they won't block). So using await in a loop will work just like you expect.


async does indeed "grow" through the code base. I usually think of this as similar to the old story about "turtles all the way down"; others have called it a "zombie virus".

I describe the deadlock situation in detail on my blog. As I state there, the best option is to allow async to grow.

If you must create a synchronous wrapper for an asynchronous method, see Stephen Toub's advice. You can use Task.Result, but you need to do two things:

  • Use ConfigureAwait(false) everywhere. This will sidestep the deadlock situation.
  • Be aware that Result has different error handling semantics.

For your particular example, something like this should suffice:

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;
  }
}

Please carefully consider the complexity before choosing a mixed synchronous/asynchronous code base. It's not as easy as it first appears.

P.S. Generally speaking, TCP/IP code should all be asynchronous anyway. It's usually a good idea to have a continuous asynchronous read going on a socket.

于 2013-01-07T02:20:51.313 回答
2

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

var readLineTask = ReadLineAsync(); 
readLineTask.Wait() 
于 2013-01-06T19:51:10.003 回答
0

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

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

为了使您的 readline 方法可以等待,它必须返回一个Taskor Task<T>

于 2013-01-06T19:53:45.373 回答