Kal*_*exx 8 .net c# asynchronous async-await dotnet-httpclient
在这种情况下,系统A需要向系统B发送消息.以下代码显示了如何完成此操作的示例:
public interface IExecutionStrategy
{
Task<Result> ExecuteMessage(Message message);
}
public class WcfExecutionStrategy
{
public async Task<Result> ExecuteMessage(Message message)
{
using (var client = new Client())
{
return await client.RunMessageOnServer(message);
}
}
}
public class MessageExecutor
{
private readonly IExecutionStrategy _strategy;
public MessageExecutor(IExecutionStrategy strategy)
{
_strategy = strategy;
}
public Task<Result> ExecuteMessage(Message msg)
{
// ....
// Do some common checks and code here
// ....
var result = await _strategy.ExecuteMessage(msg);
// ....
// Do some common cleanup and logging here
// .....
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
由于超出此问题范围的原因,我们决定从Wcf切换到使用原始http流,但我们需要并排收集指标并对其进行测试.所以我创建了一个新的IExecutionStrategy实现来处理这个:
public class HttpclientExecutionStrategy
{
public async Task<Result> ExecuteMessage(Message message)
{
var request = CreateWebRequestmessage
var responseStream = await Task.Run(() =>
{
var webResponse = (HttpWebResponse)webRequest.GetResponse();
return webResponse.GetResponseStream();
}
return MessageStreamer.ReadResultFromStream(responseStream);
}
}
Run Code Online (Sandbox Code Playgroud)
从本质上讲,我能让它成为异步的唯一方法是将其包装在一起,Task.Run()以便Web请求无阻塞.(注意:由于发送和接收的唯一流操作要求,实现这一点并不是直接的HttpClient,即使有可能这个事实超出了这个问题的范围).
我们认为这很好,直到我们阅读Stephen Cleary 关于图书馆代码和Asp.Net应用程序中有多糟糕的多篇博客文章Task.Run().这对我来说非常有意义.
如果第三方库不支持异步移动,那么实际上如何实现自然异步调用是没有意义的.例如,如果您使用的HttpClient.GetStreamAsync()是什么,这使得异步操作更好Task.Run(() => HttpClient.GetStream()),并且是否有任何方法可以解决非异步第三方库的问题?
HttpClient.GetStreamAsync是一个纯异步方法,这意味着在进行调用时不会引入新线程,并且在与组合使用时await,将产生控制权回到调用方,直到IO请求完成.这样可以很好地扩展,因为实际上在执行请求时将调用操作的ThreadPool线程释放到更多的工作,因此您的服务器实际上可以在此期间处理更多请求.
相反,使用专用线程(同步异步)只是为了进行阻塞IO请求调用肯定不会很好地扩展,如果执行时间足够长,最终可能会导致饥饿.
编辑
实现的真正异步性质XXXAsync来自向OS提供异步端点的网络设备驱动程序.在封面下WinHTTP(感谢@Noseratio for correction)库用于异步操作.这意味着生成I/O请求包(IRP)并将其传递给设备驱动程序.请求完成后,将发生CPU中断,最终导致调用的回调被调用.您可以查看这些示例:在完全异步模式下使用WinInet HTTP函数或在C++中使用Windows - 异步WinHTTP用于异步示例,当然也可以阅读Stephan Cleary 的优秀"没有线程".您可以自己实现它并将其包装在托管包装器中.
async-await如果操作是真正异步的,请使用.如果不是,那就不要假装它.
异步操作只有两个真正的好处:可伸缩性和卸载.可伸缩性主要用于服务器端,而卸载用于"特殊"线程(主要是GUI线程).
如果你是依赖于同步库并没有什么可以做的,使它异步使用Task.Run不提高可扩展性在所有(可能实际上妨碍它),你只留下了卸载.async仅当操作本质上是异步时,当整个实际异步部分(网络,磁盘等)中没有线程时,才减少资源使用
如果您正在开发富客户端应用程序,请继续使用"同步异步" async-await.但对于任何其他类型的应用程序,没有理由使用async-await,我会建议反对它.
| 归档时间: |
|
| 查看次数: |
748 次 |
| 最近记录: |