2009-09-10 62 views
3

我正在使用具有DoLookup()函数的C#编写ASP.NET Web服务。对于DoLookup()函数的每次调用,我需要我的代码执行两个单独的查询:一个到另一个远程站点的Web服务,另一个到本地数据库。在我可以编译结果并将它们作为对DoLookup方法的响应返回之前,两个查询都必须完成。我正在处理的问题是,我想尽可能提高效率,无论是在Web服务器上的响应时间和资源使用情况。我们预计每小时可以查询数千条查询。下面是我到目前为止粗略类似C#概述:使用多个长时间运行操作优化ASMX Web服务

public class SomeService : System.Web.Services.WebService 
{ 
    public SomeResponse DoLookup() 
    { 
     // Do the lookup at the remote web service and get the response 
     WebResponse wr = RemoteProvider.DoRemoteLookup(); 

     // Do the lookup at the local database and get the response 
     DBResponse dbr = DoDatabaseLookup(); 

     SomeResponse resp = new SomeResponse(wr, dbr); 

     return resp; 
    } 
} 

上面的代码做的一切顺序和伟大工程,但现在我想使它更具可扩展性。我知道我可以异步调用DoRemoteLookup()函数(RemoteProvider有BeginRemoteLookup/EndRemoteLookup方法),也可以使用BeginExecuteNonQuery/EndExecuteNonQuery方法异步执行数据库查找。

我的问题(最后)是这样的:我如何同时在单独的线程上同时触发远程Web服务查找和数据库查找,并确保它们在返回响应之前都完成了?

我想在单独的线程上执行这两个请求的原因是它们都可能有很长的响应时间(1或2秒),我想释放Web服务器的资源以处理其他请求正在等待回应。另外需要注意的是 - 我的远程Web服务查询目前是异步运行的,我只是不想让上面的示例太混乱。我正在努力的是让远程服务查找和数据库查找同时开始,并确定它们何时完成。

感谢您的任何建议。

+0

你有线程服务的线程工作吗?在网上线程任何东西是非常有限的.net平台.. – 2009-09-10 21:32:43

+0

@Charles康韦:你读过下面的答案吗?你在说什么,“有限”? – 2009-09-12 16:29:29

回答

2

你可以用一对AutoResetEvents,每个线程。在线程执行结束时,您可以调用AutoResetEvents.Set()来触发事件。

产卵后,您使用WaitAll()与两个AutoResetEvents。这将导致线程阻塞,直到两个事件都被设置。

这种方法的警告是,你必须确保Set()是保证被调用,否则你将永远阻塞。此外,确保使用线程执行适当的异常处理,否则当无应用异常导致Web应用程序重新启动时,您将无意中导致更多性能问题。

MSDN Has sample code regarding AutoResetEvent usage.

+1

为了确保您不会永远阻止使用WaitAll()的重载,该重载需要超时参数(指定可完成的操作的可接受超时)。然后,您可以检查WaitAll()的返回值,以确定它是否因为所有句柄都有信号或超时过期而返回。 – 2009-09-10 21:40:24

+0

伟大的一点。我没有假定超时,因为他想确保两人在返回之前完成。 – Alan 2009-09-10 21:54:25

0

假设你可以有一个回调函数两个web请求和数据库查找,然后沿着这些路线的东西可能工作

bool webLookupDone = false; 
bool databaseLookupDone = false; 

private void FinishedDBLookupCallBack() 
{ 
    databaseLookupDone = true; 
    if(webLookupDone) 
    { 
     FinishMethod(); 
    } 
} 

private void FinishedWebLookupCallBack() 
{ 
    webLookupDone = true; 
    if(databaseLookupDone) 
    { 
     FinishMethod(); 
    } 
} 
+0

如果两个线程在检查其他线程是否完成之前同时将done标志设置为true,则此代码具有竞争条件,因此FinishMethod将被调用两次。 – DSO 2009-09-10 21:37:09

+0

这个想法已经超越了我的想法,但我不知道如何防止它。我不太熟悉多线程。 – Bela 2009-09-11 15:49:06

+0

不难解决,只需在每个方法周围放置一个锁,以便完成标志的设置和对其他完成标志的检查是自动完成的。 – DSO 2009-09-14 21:30:53

1

Asynchronous XML Web Service MethodsHow to: Create Asynchronous Web Service MethodsHow to: Chain Asynchronous Calls with a Web Service Method

但要注意这些文章的第一段:

本主题是特定于传统技术。现在应使用Windows Communication Foundation (WCF)创建XML Web服务和XML Web服务客户端。


BTW,做事这些文章说的方式是重要的,因为它释放了ASP.NET辅助线程,而长时间运行的任务运行。否则,您可能会阻止工作线程,阻止它服务于其他请求,并影响可伸缩性。

+0

在这种情况下,这些调用需要同时执行。 WebsService调用本身不是异步的 - 它必须在将结果返回给调用者之前完成查找。 – Alan 2009-09-10 21:35:20

+1

我不明白为什么你不能让这些技术工作。如果你认为你的两个异步方法是单一的复合异步方法,那么你应该可以使用http://msdn.microsoft.com/en-us/library/bb559019.aspx – 2009-09-11 00:04:47

+0

谢谢你的链接约翰。我打算在使DoLookup调用异步后调用其内部方法。我会看看你提供的链接。 – TLiebe 2009-09-11 14:32:56

0

我想我没有足够的代表upvote或评论。所以这是对约翰桑德斯答案和艾伦评论的评论。

如果您担心可扩展性和资源消耗,那么您一定想与John的答案一起使用。

这里有两个注意事项:加速单个请求,并使系统高效地处理许多并发请求。前者都是通过并行执行外部呼叫来实现Alan和John的答案。

后者,这听起来像这是你的主要关注,是由线程阻塞的任何地方,也就是约翰的回答没有实现。

不要产生自己的线程。线程非常昂贵,并且如果使用.net框架提供的异步方法,IO线程池中已经有大量线程可以处理您的外部调用。

您的服务的webmethod也需要同步。否则,一个工作线程将被阻塞,直到你的外部调用完成(即使它们并行运行,它仍然是1-2秒)。每个处理传入请求的CPU只有12个线程(如果您的machine.config根据recommendation设置)。您最多可以处理12个并发请求(乘以CPU数量)。另一方面,如果你的web方法是异步的,Be​​gin会立即返回,并且线程返回到工作线程池准备处理另一个传入请求,而你的外部调用被IO完成端口等待,它们将在那里由IO线程池中的线程处理,一旦它们返回。

+0

谢谢转机。我计划在有一个BeginLookup()和EndLookup()事件后,让其他所有工作都开始。我确实为连续调用远程Web服务和数据库创建了Begin/End Lookup()版本 - 现在我只需制作一个异步版本,并反过来将其调用为内部调用。 – TLiebe 2009-09-11 13:06:03