繁体   English   中英

异步方法如何在C#中工作?

[英]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 ThreadPoolIAsyncResult如何知道调用已完成并且是时候调用CallBack方法了?

代码是铁路,线程是火车。 当火车进入铁路时,它会执行代码。

BeginMyMethod由主线程执行。 如果您查看BeginMyMethod它只需将MyMethod的委托添加到ThreadPool的队列中。 实际的MyMethod由列车的一列列车执行。 完成MyMethodMyMethod的完成例程由执行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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM