为什么异步委托方法需要调用EndInvoke?
为什么委托需要在方法触发之前调用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"); } }
你需要调用EndInvoke
的原因是为了避免内存泄漏; .Net将存储有关函数结果(或exception)的信息,直到您调用EndInvoke
。
您可以在为BeginInvoke
提供的完成处理程序中调用EndInvoke
,并保留异步性质。
编辑 :
例如:
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(); });
正如SLaks所说, EndInvoke
可以防止内存泄漏。
BeginInvoke
仍然是异步的; 考虑以下代码:
static void Main() { Func slowCalculator = new Func (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
调用的情况下编写的,那么在Main
可以完成其余的“很多东西”之前,必须完成PerformSlowCalculation
; 这样,两者可以同时发生。
现在,在使用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(); }