为什么异步委托方法需要调用EndInvoke?

时间:2009-11-11 03:04:18

标签: c# asynchronous delegates

为什么委托需要在方法触发之前调用EndInvoke?如果我需要调用EndInvoke(它阻塞线程)那么它实际上不是异步调用吗?

这是我试图运行的代码。

class Program
    {
        private delegate void GenerateXmlDelegate();

        static void Main(string[] args)
        {
            GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
            IAsyncResult result = worker.BeginInvoke(null, null);
        }

        private static void GenerateMainXml()
        {
            Thread.Sleep(10000);
            Console.WriteLine("GenerateMainXml Called by delegate");
        }
    }

2 个答案:

答案 0 :(得分:16)

您需要调用EndInvoke的原因是为了避免内存泄漏; .Net将存储有关函数结果(或异常)的信息,直到您调用EndInvoke

您可以在提供给EndInvoke的完成处理程序中调用BeginInvoke并保留异步性质。

修改

例如:

class Program {
    private delegate void GenerateXmlDelegate();

    static void Main(string[] args) {
        GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
        IAsyncResult result = worker.BeginInvoke(delegate {
            try {
                worker.EndInvoke();
            } catch(...) { ... }
        }, null);
    }

    private static void GenerateMainXml() {
        Thread.Sleep(10000);
        Console.WriteLine("GenerateMainXml Called by delegate");
    }
}

如果要发起异步调用而忘记它,可以使用ThreadPool,如下所示:

ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); });

答案 1 :(得分:6)

正如SLaks所说,EndInvoke可以防止内存泄漏。

BeginInvoke仍然是异步的;请考虑以下代码:

static void Main() {
    Func<double> slowCalculator = new Func<double>(PerformSlowCalculation);
    IAsyncResult slowCalculation = slowCalculator.BeginInvoke(null, null);

    // lots of stuff to do while slowCalculator is doing its thing

    Console.WriteLine("Result is {0}", slowCalculator.EndInvoke(slowCalculation));
}

static double PerformSlowCalculation() {
    double result;

    // lots and lots of code

    return result;
}

如果此代码是在没有BeginInvoke / EndInvoke调用的情况下编写的,则PerformSlowCalculation必须在Main完成剩余的“大量内容”之前完成;这样,两者可以同时发生。

现在,在您使用GenerateXmlDelegate的示例中,即使您没有返回任何内容,仍然需要EndInvoke。这样做的方法是:

static void Main(string[] args) {
    GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
    IAsyncResult result = worker.BeginInvoke(GenerateXmlComplete, null);
}

private static void GenerateXmlComplete(IAsyncResult result) {
    AsyncResult realResult = result as AsyncResult;
    GenerateXmlDelegate worker = result.AsyncDelegate as GenerateXmlDelegate;
    worker.EndInvoke();
}