2009-10-24 55 views
7

我在我的一些项目中使用异步方法,我喜欢它,因为它允许我的应用程序具有更多的可伸缩性。但是,我想知道异步方法在后台真正起作用吗? .NET(或Windows?)如何知道呼叫已完成?根据我所做的异步调用的数量,我可以看到创建了新线程(并不总是......)。为什么?异步方法在C#中如何工作?

此外,我想监视一个请求需要多长时间才能完成。为了测试这个概念,我编写了下面的代码,该代码异步调用Web服务并在启动秒表后立即调用。

for (int i = 0; i < 10000; i++) 
{ 
    myWebService.BeginMyMethod(new MyRequest(), result, new AsyncCallback(callback), i); 
    stopWatches[i].Start(); 
} 
// Call back stop the stopwatch after calling EndMyMethod 

这并不工作,因为所有的请求(10000)具有相同的开始时间和持续时间将直线上升(称之为0 = 1时长,通话1 = 2的持续时间等)。我如何使用异步方法(从请求真正执行到结束的那一刻)监视实际的呼叫持续时间?


UPDATE:是否异步方法阻塞流动?我知道它使用.NET ThreadPool,但IAsyncResult如何知道呼叫已完成,是时候调用CallBack方法了?

+0

1. ThreadPool,2.查看有关ThreadPool如何工作的详细信息,但我不认为通过一般方式可以实现您想要的功能。 http://msdn.microsoft.com/en-us/library/ms973903.aspx – 2009-10-24 00:17:57

回答

3

该代码是铁路和线程是火车。当火车驶上铁路时,它执行代码。

BeginMyMethod由主线程执行。如果您查看BeginMyMethod,则只需将MyMethod的代理人添加到ThreadPool的队列中即可。实际的MyMethod由火车游泳池的列车之一执行。当MyMethod完成时调用的完成例程由执行MyMethod的相同线程执行,而不是由运行代码其余部分的主线程执行。当一个线程池线程忙于执行MyMethod时,主线程可以乘坐铁路系统的其他部分(执行一些其他代码),或者干脆睡觉,等待某个信号灯点亮。

因此,不知道什么时候可以调用完成例程,相反,完成例程仅仅是线程池线程在完成执行MyMethod后调用的委托。

我希望你不要介意有点幼稚的火车比喻,我知道它在向人们解释多线程时不止一次地帮助我。

+0

我喜欢火车的比喻!谢谢! :) – Martin 2009-10-24 01:40:30

1

问题的关键是呼叫Begin排队请求执行您的方法。该方法实际上是在ThreadPool上执行的,ThreadPool是由运行时提供的一组工作线程。

线程池是一组固定的线程,用于在异步任务进入队列时收敛。这就解释了为什么你会看到执行时间需要更长和更长的时间 - 你的方法可能每个都在大约相同的时间执行,但是直到队列中所有先前的方法都执行完毕才开始执行。

要监视实际执行异步方法所需的时间长度,必须在方法的开始和结束处启动和停止计时器。

下面是ThreadPool类的文档和关于async methods的文章,它们可以更好地解释发生了什么。

1

异步方法通过使用.NET ThreadPool工作。他们会将工作推到ThreadPool线程(如果需要,可能会创建一个线程,但通常只是重用一个线程)以便在后台工作。

就你而言,你可以做你正在做的事情,但是,要意识到ThreadPool只有有限数量的线程可以工作。你将把你的工作产生到后台线程上,第一个会立即运行,但是一段时间后,他们会排队等待,直到完成“任务”才运行。这将使线程的外观变得越来越长。

但是,您的秒表标准有点不妥。您应该测量完成N个任务所需的总时间,而不是完成一项任务的N次。这将是一个更有用的指标。

0

其可能大部分执行时间发生在BeginMyMethod()之前。在这种情况下,你的测量值将会太低。实际上,根据API,BeginMyMethod()可能会在离开堆栈之前调用回调函数。然后将呼叫移至StopWatch.Start()应该会有所帮助。