我在我的一些项目中使用异步方法,我喜欢它,因为它使我的应用程序更具可扩展性。但是,我想知道异步方法如何在后台真正工作?.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 时,主线程可以乘坐铁路系统的其他部分(执行其他一些代码),或者只是睡觉,等待直到某些信号量被点亮。

因此,没有 IAsyncResult &quot;知道&quot;何时调用完成例程,完成例程只是线程池的线程在执行 MyMethod 后立即调用的委托。

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

其他提示

它的关键是调用 Begin 排队请求以执行您的方法。该方法实际上是在ThreadPool上执行的,ThreadPool是运行时提供的一组工作线程。

线程池是一组固定的线程,用于在异步任务进入队列时处理它们。这就解释了为什么你看到执行时间越来越长 - 你的方法可能会在大致相同的时间内执行,但是在队列中所有先前的方法都被执行之前它们才会启动。

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

以下是 ThreadPool 课程的文档和文章关于异步方法,可以更好地解释正在发生的事情。

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

就您而言,您可以做您正在做的事情,但是,请意识到 ThreadPool 它可以使用的线程数量有限。您将把您的工作生成到后台线程上,第一个线程将立即运行,但过了一会儿,它们将排队,直到“任务”完全运行之前才开始工作。这将使线程的出现花费越来越长的时间。

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

大部分执行时间可能发生在 BeginMyMethod()之前。在这种情况下,您的测量结果会太低。实际上,根据API, BeginMyMethod()可能会在离开堆栈本身之前调用回调。将调用提升到 StopWatch.Start()应该会有所帮助。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top