C# 如何更新API以使用async关键字,而不为所有调用者使用Wait
我试图使用C# 如何更新API以使用async关键字,而不为所有调用者使用Wait,c#,.net,.net-4.5,async-await,C#,.net,.net 4.5,Async Await,我试图使用StreamSocket和DataReader将一些TcpClient依赖代码移植到.NET4.5 我有一个名为ReadLine()的函数,在任何地方都可以使用。通过在此代码的正文(LoadAsync())中使用DataReader,我的方法被强制标记为async关键字 连锁反应如下: 现在我有数百个地方需要向调用方法添加async,并将wait应用于底层async方法调用 这就引出了我的下一个问题。。。 有没有一种简单的方法可以包装ReadLine(),这样调用方法就不会知道它是一个
StreamSocket
和DataReader
将一些TcpClient
依赖代码移植到.NET4.5
我有一个名为ReadLine()
的函数,在任何地方都可以使用。通过在此代码的正文(LoadAsync()
)中使用DataReader
,我的方法被强制标记为async
关键字
连锁反应如下:
现在我有数百个地方需要向调用方法添加async
,并将wait应用于底层async
方法调用
这就引出了我的下一个问题。。。
有没有一种简单的方法可以包装ReadLine()
,这样调用方法就不会知道它是一个异步方法,这样我就不必更改其余的代码了
还有。。。
我经常在多个地方的循环中使用此方法调用。如果这些方法现在标记为
async
,我担心我可能会在不应该的时候从流中读取数据,这将导致各种恶梦。这是个问题还是我想得太远了?制作一个ReadLineSync函数和一个ReadLine函数。在ReadLine函数中,可以如下方式调用ReadLineSync:
var readLineTask = ReadLineAsync();
readLineTask.Wait()
将它标记为异步并不意味着无论何时调用它都必须等待它。之所以将其标记为异步,是因为在方法中使用了wait 这意味着您不必仅仅因为在那里调用
ReadLine()
就将其他方法标记为异步
要让readline方法等待,它必须返回任务
或任务
还有。。。我经常在多个地方的循环中使用此方法调用。如果这些方法现在标记为异步,我担心我可能会在不应该的时候从流中读取数据,这会引起各种恶梦。这是个问题还是我想得太远了
如果在调用*Async
方法时始终使用wait
,则Async
方法的行为将与同步方法一样(除非它们不会阻塞)。因此,在循环中使用wait
将像您预期的那样工作
async
确实通过代码库“增长”。我通常认为这类似于关于“海龟一路下来”的老故事;其他人称之为“僵尸病毒”
我在我的博客上详细描述了。正如我在这里指出的,最好的选择是允许async
增长
如果您必须创建一个。您可以使用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;
}
}
private异步任务ReadLineAsync()
{
…//*Every*在此方法及其调用的每个方法中等待
//必须使用ConfigureWait(false)。
}
公共字符串读取行()
{
尝试
{
返回ReadLineAsync()。结果;
}
捕获(聚合异常)
{
ExceptionDispatchInfo.Capture(例如InnerException.Throw();
投掷;
}
}
在选择混合同步/异步代码库之前,请仔细考虑复杂性。这并不像第一次出现的那么容易
另外,一般来说,TCP/IP代码无论如何都应该是异步的。在套接字上进行连续异步读取通常是个好主意。您真的需要使ReadLine异步吗?我不希望它是异步的,但是因为我在这个方法中使用了wait,编译器强迫我用async来标记它,这会引发连锁反应。将它标记为async并不意味着每次调用它时都要等待它。您之所以将其标记为异步,是因为您在方法中使用了wait。我应该提到ReadLine()是一个返回任务的函数。@c0D3l0g1c Ok,但它是否实现了所有其他可等待的要求?i、 e.GetAwaiter/BeginAwait/EndAwait?如果确实如此,那么您必须修改您的代码,正如您所描述的:)这将使编译器满意,但它不会等待ReadLine完成。你现在有了一个比赛条件。请注意,这至少会在WinForms和ASP.NET中导致确定性死锁。您的建议非常有意义。在ReadLine方法中,我调用Result.Perfect,而不是等待ReadLineAsyn。任务完成后,调用任务结果。回答得很好!优秀的博客文章!