如何在ASP.NET中等待异步Web服务调用的结果以获得最佳性能

7
在WebForms ASP.NET站点(IIS,单个应用程序池)中,我调用了在Visual Studio中引用的较长的网络服务方法,其为Service Reference(.NET 4.0)。不幸的是,在向用户提供页面之前,我必须等待来自Web服务的信息。目前,网络服务被同步调用,因此服务器无法重用当前线程以处理其他请求,这对性能有影响。
当然,我可以在Visual Studio中为服务引用生成异步操作,并调用BeginGetFoo而不是GetFoo,但仍然必须以某种方式等待来自Web服务的结果。
问题来了。如果我使用AsyncWaitHandle.WaitOne(如下所示),从整个应用程序性能方面来看,它是否比我今天使用的同步调用更好?
IAsyncResult result = fooSoapClient.BeginGetFoo();
result.AsyncWaitHandle.WaitOne();
var foo = fooSoapClient.EndGetFoo(result);

当然,如果有更好的等待方式,欢迎提出建议。


你可能想阅读以下文档:http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.100).aspx 作为对你主观问题的回答。你没有提供足够的信息。 - Security Hound
为了获得最佳性能,不要等待,而是设置连续性。您发布的代码与同步调用几乎相同。 - millimoose
@Ramhound - 我已经阅读了。您需要什么信息,我很乐意添加它? - Pol
3个回答

10

由于 Web 服务调用嵌套在多个页面中使用的业务逻辑类中,所以我无法轻松地使用 AddOnPreRenderCompleteAsync(),必须进行大量的重构。此外,EndEventHandler 可能在不同的线程中执行,这是另一个需要重构的难题。 - Pol
你不能在不暴露异步操作的情况下执行异步任务。除非你的代码使用了ThreadStatic字段,否则EndEventHandler在不同线程中执行这一事实并不重要。 - Stilgar
@John Saunders - 使用AddOnPreRenderCompleteAsync,是否可以同时调用Web服务3次,并在这3个调用完成后返回? - Pol
是的,这就是它的作用。异步操作是Web服务调用、数据库调用或其他任何操作都无关紧要。 - John Saunders
@JohnSaunders - 我明白了,但是怎么做呢?当我调用 Web 服务 3 次时,我会得到 3 个 IAsyncResults,但是对于 AddOnPreRenderCompleteAsync,我只需要一个。我可以链接 IAsyncResults,但我不想链接,我想一次性开始所有 3 个调用。 - Pol
显示剩余3条评论

0

你仍然会占用线程。一个“安全”的选择是使用ASP.NET MVC的异步控制器:http://www.aaronstannard.com/post/2011/01/06/asynchonrous-controllers-ASPNET-mvc.aspx

但理想情况下,不应该在Web请求上执行长时间运行的任务。可以有一个Windows服务或其他进程处理长时间运行的任务(可以通过Web请求将其放入消息队列或将任务放入数据库中),并使用ajax或其他方式从客户端轮询,然后在完成时更新用户。


我知道我可以改变整个设计来避免这个问题,但说起来容易做起来难。 - Pol
他为什么要在Web Forms项目中添加MVC,只是为了获得异步行为,而Web Forms自MVC项目开始之前就支持异步页面(还有服务和处理程序)? - Stilgar
异步页面/处理程序可以实现相同的结果,但这样长时间运行的任务不应该在请求中完成(应用程序池回收等)。 - ashic
这取决于任务运行的时间长短。如果在页面加载时让用户等待是可以接受的,那么在请求中运行这些任务也是可以接受的。这不像应用程序池会在请求中途回收。 - Stilgar
当然这取决于情况。只要ASP.NET知道有操作正在进行,那么就应该是安全的。如果是后台线程在执行,ASP.NET将不会知道。这篇文章值得一读:http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx - ashic
在这种情况下,操作是在Web请求的上下文中进行的。在所有已启动的请求结束之前,IIS不会回收池。Phil Haack的博客文章讨论了在ASP.NET中旋转线程的问题。 - Stilgar

0
如果重构代码不可接受,因此您无法遵循@John Saunders的答案,那么您唯一能做的就是增加应用程序的线程数。这将使您能够更好地扩展,但在某些时候它会有递减的回报,并且您将开始影响性能。更重要的是,如果您没有用户等待请求队列(即服务器上每个核心超过25个并发用户),则无需执行任何操作。Web服务器中的异步编程仅有助于可伸缩性,而不是单个用户的实际性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接