实现HttpWebRequest异步方法

本文关键字:异步方法 HttpWebRequest 实现 | 更新日期: 2023-09-27 18:24:34

由于各种原因,我一直致力于更改现有的同步IO绑定代码,例如在我们使用的服务中非常频繁地使用HttpWebRequest类发送出站HTTP请求。

我知道async/await以及对.NET 4.5的更改,但我们目前使用的是.NET 4.0。我也知道Microsoft.Bsl.Async,由于其他原因,这目前不是一个选项。

我使用本文中关于异步的示例代码和HttpWebRequest作为参考。

我的问题是,如果我没有更新UI,或者在BeginXXXX和EndXXXX之间做其他事情,但出站IO调用的时间各为40秒以上,那么值得实现这种异步吗,还是应该坚持同步执行?

实现HttpWebRequest异步方法

我认为这绝对值得。这是一个主观判断调用,尤其是在服务器端,但40秒非常重要。假设您的服务不受CPU限制,我认为大约0.5秒就足够快了,您可以考虑使其同步。在40秒内,一定要异步。

如果您使用的是带有.NET 4.0的ASP.NET,则不能使用Microsoft.Bcl.Async。但是,如果您的服务是其他服务(例如Win32服务),则可以使用Microsoft.Bcl.Async。无论哪种方式,都要计划在可能的时候升级到.NET 4.5。你即将发现async为你省去了多少痛苦。

关于您的代码结构,我推荐两种方法之一:

  1. 使用基于事件的异步模式(EAP)
  2. 在异步编程模型(APM)API周围使用Task包装器

EAP方法更干净。对于EAP,您应该使用WebClient而不是HttpRequest。例如,调用DownloadStringAsync方法并处理DownloadStringCompleted事件。这样做的好处是,EAP将通知当前上下文异步操作正在进行,在操作完成时再次通知它,并使用该上下文执行事件处理程序。如果您托管在ASP.NET中,这一点尤为重要。

EAP模式的缺点是它总是使用上下文(即使您不需要它)。

Task APM包装器方法需要做更多的工作。使用这种方法,您可以使用TaskFactory.FromAsync来创建Task——围绕Begin/End对返回方法。然后使用返回的Task<T>上的成员来安排完成(Task.ContinueWith)。

Task APM包装方法的缺点是它从不使用上下文,因此如果您托管在ASP.NET上,则需要自己进行通知(SynchronizationContext.OperationStartedSynchronizationContext.OperationCompleted)。您还(可能)必须捕获上下文(TaskScheduler.FromCurrentSynchronizationContext),并在计划延续时将其传递给ContinueWith,以便它们在该上下文中运行。

如果您正在创建一个供其余代码使用的实际组件,那么Task APM包装方法还有另一个优点:它更容易转换为async/await使用的基于任务的异步模式。