【问题标题】:How asynchronous methods work in C#?C# 中的异步方法如何工作?
【发布时间】:2009-10-24 00:12:02
【问题描述】:

我在我的一些项目中使用异步方法,我喜欢它,因为它使我的应用程序更具可扩展性。但是,我想知道异步方法如何在后台真正工作? .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 方法了?

【问题讨论】:

标签: c# .net-3.5 asynchronous


【解决方案1】:

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

BeginMyMethod 由主线程执行。如果您查看BeginMyMethod 内部,它只是将MyMethod 的代表添加到ThreadPool 的队列中。实际的MyMethod 由火车池中的一列火车执行。当MyMethod 完成时调用的完成例程由执行MyMethod 的同一线程执行,而不是由运行其余代码的主线程执行。当线程池线程忙于执行MyMethod 时,主线程可以骑在铁路系统的其他部分(执行其他代码),或者只是休眠,等待某个信号灯亮起。

因此,没有IAsyncResult“知道”何时调用完成例程之类的东西,相反,完成例程只是线程池的线程在执行完MyMethod后立即调用的委托。

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

【讨论】:

  • 我喜欢火车的比喻!谢谢! :)
【解决方案2】:

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

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

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

这里是 ThreadPool 类的文档,以及一篇关于 async methods 的文章,可以更好地解释发生了什么。

【讨论】:

    【解决方案3】:

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

    在你的情况下,你可以做你正在做的事情,但是,要意识到ThreadPool 的线程数量是有限的。您将在后台线程上生成您的工作,第一个线程将立即运行,但过了一段时间,它们将排队,并且在“任务”完全运行之前不会工作。这将使线程的外观花费越来越长的时间。

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-02
        • 2011-07-05
        • 2014-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多