如何在 ASP.NET 中等待异步 Web 服务调用的结果以获得最佳性能
Posted
技术标签:
【中文标题】如何在 ASP.NET 中等待异步 Web 服务调用的结果以获得最佳性能【英文标题】:How to wait for result of asynchronous web service call in ASP.NET for best performance 【发布时间】:2012-02-08 13:52:19 【问题描述】:在 WebForms ASP.NET 站点(IIS,单个应用程序池)中,我调用了在 Visual Studio 作为服务参考 (.NET 4.0) 中引用的冗长 Web 服务方法。不幸的是,我必须等待来自网络服务的信息,然后才能向用户提供页面。目前 web 服务是同步调用的,所以服务器不能重用当前线程来处理其他影响性能的请求。
当然,我可以在 Visual Studio 中为服务引用生成异步操作并调用 BeginGetFoo
而不是 GetFoo
,但我仍然必须以某种方式等待来自 Web 服务的结果。
问题来了。如果我使用AsyncWaitHandle.WaitOne
(如下),我今天使用的同步调用在整个应用程序性能方面会更好吗?
IAsyncResult result = fooSoapClient.BeginGetFoo();
result.AsyncWaitHandle.WaitOne();
var foo = fooSoapClient.EndGetFoo(result);
当然,如果等待可以做得更好,我愿意接受建议。
【问题讨论】:
您可能需要阅读以下文档:msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.100).aspx 作为对您主观问题的回答。您没有提供足够的信息 为了获得最佳性能,不要等待,而是设置延续。您发布的代码与同步调用几乎相同。 @Ramhound - 我读过。您需要什么信息,我很乐意补充? 【参考方案1】:您想使用异步页面。请参阅“Wicked Code: Scalable Apps with Asynchronous Programming in ASP.NET”和Asynchronous Pages in ASP.NET 2.0,其中使用RegisterAsyncTask 讨论Web 服务和异步任务。
【讨论】:
我不能在没有大量重构的情况下使用AddOnPreRenderCompleteAsync()
,因为 Web 服务调用位于许多页面中使用的业务逻辑类的深处。而EndEventHandler
可以在不同的线程中执行,这是另一个重构挑战。
好吧,如果不显示异步操作,您就无法执行异步操作。 EndEventHandler 在不同线程中执行的事实应该无关紧要,除非由于某种原因您的代码使用 ThreadStatic 字段。
@John Saunders - AddOnPreRenderCompleteAsync
是否可以一次调用 Web 服务 3 次并在这 3 个调用完成后返回?
是的。这就是它的用途。异步操作是 Web 服务调用、数据库调用还是其他什么都没有关系。
@JohnSaunders - 我明白,但是怎么做呢?当我调用网络服务 3 次时,我将拥有 3 个 IAsyncResults,但对于 AddOnPreRenderCompleteAsync
,我只需要一个。我可以链接 IAsyncResults 但我不想链接,我想同时开始所有 3 个调用。【参考方案2】:
您仍然会占用线程。 “安全”选项是使用 ASP.NET MVC 的异步控制器:http://www.aaronstannard.com/post/2011/01/06/asynchonrous-controllers-ASPNET-mvc.aspx
不过,理想情况下,您不应该对 Web 请求执行长时间运行的操作。让 Windows 服务或其他东西处理长时间运行的任务(可以通过 Web 请求在消息队列中删除某些内容或将任务放入数据库中启动)并使用 ajax 或其他东西从客户端轮询,然后在何时更新用户完成了。
【讨论】:
我知道我可以改变整个设计来避免这个问题,这很容易说:-) 在 MVC 项目启动之前,当 Web 窗体支持异步页面(也包括服务和处理程序)时,他为什么要将 MVC 添加到他的 Web 窗体项目中以获得异步行为? 异步页面/处理程序将获得相同的结果,但无论如何都不应该对请求执行如此长时间运行的任务(应用程序池回收等)。 这取决于任务运行的时间。如果在页面加载时让用户等待是可以接受的,那么在请求上运行这些任务当然是可以接受的。应用程序池不会在请求中间回收。 当然取决于。只要 ASP.NET 知道有待处理的操作,它就应该是安全的。如果是后台线程在做,ASP.NET 不会知道。这值得一读:haacked.com/archive/2011/10/16/…【参考方案3】:如果重构您的代码是不可接受的,因此您无法遵循@John Saunders 的回答,那么您唯一能做的就是增加应用程序的线程数。这将使您能够更好地扩展,但在某些时候它的收益会递减,并且您将开始损害性能。更重要的是,如果您没有用户在请求队列中等待(即服务器上的每个核心同时有超过 25 个用户),您无需执行任何操作。 Web 服务器中的异步编程仅有助于提高可扩展性,但对单个用户没有实际性能。
【讨论】:
以上是关于如何在 ASP.NET 中等待异步 Web 服务调用的结果以获得最佳性能的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Web 表单 - 如何异步调用 WCF 异步方法?
如何使 ASP.NET Core Web API 操作异步执行?