在这种情况下,系统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;
}
}
由于超出此问题范围的原因,我们决定从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);
}
}
基本上,我可以将其设置为异步的唯一方法是将其包装在Task.Run()
中,以便Web请求无阻塞。 (注意:由于发送和接收的唯一流操作要求,实现这一点并不是直接在HttpClient
,即使可能这个事实超出此范围问题)。
我们认为这很好,直到我们在库代码和Asp.Net应用程序中阅读Stephen Cleary's multiple blog posts关于Task.Run()
如何不好的问题。这对我来说非常有意义。
如果第三方库不支持异步移动,那么实际上如何实现自然异步调用是没有意义的。例如,如果您使用HttpClient.GetStreamAsync()
那么这样做会使异步操作比Task.Run(() => HttpClient.GetStream())
更好,并且有没有办法为非异步第三方库解决这个问题?
答案 0 :(得分:9)
HttpClient.GetStreamAsync
是一个纯异步方法,这意味着在进行调用时不会引入新线程,并且在与await
结合使用时,会将控制权交还给调用者,直到IO请求为止已经完成了。这将很好地扩展,因为您实际上释放调用操作的ThreadPool线程在执行请求时执行更多工作,因此您的服务器实际上可以在此期间处理更多请求。
相反,使用专用线程(同步异步)只是为了阻止IO请求调用肯定不会很好地扩展,如果执行时间足够长,最终可能会导致饥饿。
修改
XXXAsync
实现的真正异步性质来自向OS提供异步端点的网络设备驱动程序。在幕后,WinHTTP
(感谢@Noseratio用于更正)库用于异步操作。这意味着生成I / O请求包(IRP)并将其传递给设备驱动程序。请求完成后,将发生CPU中断,最终导致调用的回调被调用。您可以查看这些示例:Using WinInet HTTP functions in Full Asynchronous Mode或Windows with C++ - Asynchronous WinHTTP以获取异步示例,当然还可以阅读Stephan Cleary的优秀There Is No Thread。您可以自己实现它并将其包装在托管包装中。
答案 1 :(得分:6)
如果操作是真正异步的,请使用async-await
。如果不是,那就不要假装它。
异步操作只有两个真正的好处:可伸缩性和卸载。可伸缩性主要用于服务器端,而卸载用于&#34;特殊&#34; 线程(主要是GUI
线程)。
如果您依赖同步库并且无法做任何事情,那么使用Task.Run
使其异步并不能提高可扩展性 >(实际上可能会阻碍它),而你只能卸下。 async
仅在操作本质上是异步时,在整个实际异步部分(网络,磁盘等)中there is no thread时减少资源使用
如果您正在开发富客户端应用程序,请继续使用&#34;同步异步&#34;与async-await
。但对于任何其他类型的应用程序,没有理由使用async-await
,我建议不要使用它。