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

10 c# delegates asynchronous

为什么委托需要在方法触发之前调用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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

SLa*_*aks 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要激活异步调用并忘记它,可以使用ThreadPool,如下所示:

ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); });
Run Code Online (Sandbox Code Playgroud)

  • 这只是有点正确 - 不会发生内存泄漏。https://gist.github.com/jcdickinson/9109599。但是,在某些情况下,某些跟踪是使用“Begin/End-Invoke”对完成的 - 一个示例是:如果您不对“Socket”操作调用“End*”,则您的套接字性能计数器将完全失控(没有内存泄漏,这些值将非常不正确)。 (2认同)

Dan*_*Tao 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;
}
Run Code Online (Sandbox Code Playgroud)

如果这段代码是在没有BeginInvoke/ EndInvokecalls的情况下编写的,则PerformSlowCalculation必须先完成Main才能完成其余的"很多东西"; 这样,两者可以同时发生.

现在,在你使用a的例子中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();
}
Run Code Online (Sandbox Code Playgroud)