[英]How asynchronous methods work in C#?
我在我的一些项目中使用异步方法,我喜欢它,因为它允许我的应用程序更具可伸缩性。 但是,我想知道异步方法在后台如何真正起作用? .NET(或Windows?)如何知道呼叫已完成? 根据我所做的异步调用的数量,我可以看到创建了新线程(但并不总是......)。 为什么?
另外,我想监控请求完成的时间。 为了测试这个概念,我编写了以下代码,它在启动秒表后立即异步调用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等)。 如何使用异步方法监控呼叫的实际持续时间(从请求真正执行到结束的那一刻)?
更新 :异步方法是否会阻止流程? 我知道它使用.NET ThreadPool
但IAsyncResult
如何知道调用已完成并且是时候调用CallBack
方法了?
代码是铁路,线程是火车。 当火车进入铁路时,它会执行代码。
BeginMyMethod
由主线程执行。 如果您查看BeginMyMethod
它只需将MyMethod
的委托添加到ThreadPool
的队列中。 实际的MyMethod
由列车的一列列车执行。 完成MyMethod
时MyMethod
的完成例程由执行MyMethod
的同一线程执行,而不是由运行其余代码的主线程执行。 当一个线程池线程忙于执行MyMethod
,主线程可以乘坐铁路系统的其他部分(执行一些其他代码),或者只是睡觉,等待直到某些信号量被点亮。
因此,没有IAsyncResult
“知道”什么时候调用完成例程,相反,完成例程只是线程池的线程在完成执行MyMethod
之后调用的委托。
我希望你不介意有些幼稚的火车比喻,我知道在向人们解释多线程时它不止一次帮助了我。
它的关键是调用Begin
排队请求执行您的方法。 该方法实际上是在ThreadPool上执行的,ThreadPool是运行时提供的一组工作线程。
线程池是一组固定的线程,用于在异步任务进入队列时处理它们。 这就解释了为什么你看到执行时间越来越长 - 你的方法可能会在大致相同的时间内执行,但是直到队列中的所有先前方法都被执行后才会开始执行。
要监视实际执行异步方法所需的时间长度,您必须在方法的开头和结尾处启动和停止计时器。
这是ThreadPool类的文档,以及一篇关于异步方法的文章,它们更好地解释了正在发生的事情。
异步方法使用.NET ThreadPool
。 他们会将工作推送到ThreadPool
线程(如果需要,可能会创建一个,但通常只重用一个),以便在后台工作。
在你的情况下,你可以做你正在做的事情,但是,要意识到ThreadPool
具有有限数量的线程,它将使用它。 你将把你的工作产生到后台线程上,第一个会立即运行,但过了一段时间,它们会排队,直到“任务”完全运行之后才能工作。 这将使线程的外观花费更长和更长时间。
但是,你的秒表标准有些缺陷。 您应该测量完成N个任务所需的总时间,而不是完成一个任务的N次。 这将是一个更有用的指标。
大多数执行时间可能发生在BeginMyMethod()
之前。 在这种情况下,您的测量结果会太低。 实际上,取决于API, BeginMyMethod()
可以在离开堆栈本身之前调用回调。 将调用提升到StopWatch.Start()
应该会有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.