开始结束异步方法调用

时间:2014-05-17 03:56:58

标签: c# multithreading asynchronous .net-3.5 begininvoke

以下是Microsoft的代码段。 我对异步方法调用有疑问。

因为我们正在调用end.Invoke在Begin-invoke之后看起来我们正在进行同步调用。因为我们正在等待异步调用的返回值。

如果在调用end.invoke时异步方法没有完成,会发生什么。 我们可以继续下一个陈述,或者我们必须等待。

如果在多线程环境中发生这种情况,他们如何处理回调信号以纠正线程。

public void DemoEndInvoke()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Initiate the asynchronous call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);  

    // Do some useful work here. This would be work you want to have
    // run at the same time as the asynchronous call.

    // Retrieve the results of the asynchronous call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;  

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                               and the number {1}", s, iExecThread.ToString() ) );
}

2 个答案:

答案 0 :(得分:5)

  

如果异步方法没有完成,会发生什么   调用end.invoke。我们可以继续进行下一次发言吗?   等等。

是的,EndInvoke是阻止通话。如果使用TaskFactory.FromAsync方法,可以使整个事情更容易使用。这将转换您的API以返回您可以await的任务。

你的代码应该是这样的(我还没有编译它):

public async void DemoEndInvoke()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    await Task.Factory.FromAsync(MethodDelegate.BeginInvoke, MethodDelegate.EndInvoke, iExecThread);

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", and the number {1}", s, iExecThread.ToString() ) );
}

使用await编译器将生成一个状态机,该状态机保存当前SynchronizationContext,然后在任务完成后恢复它,并在同一SynchronizationContext上执行该方法的其余部分。如果您在UI线程上await,则await之后的代码也将在UI线程上执行。但是对于控制台应用程序和单元测试来说并非如此。

如果你要做的只是在后台线程上运行一个长时间运行的方法,你只需在.net 4.5中使用Task.Run或在.net 4.0中使用TaskFactory.StartNew即可。有关两者之间的差异,请参阅此article

public async void DemoEndInvoke()
{
    await Task.Run(() => this.LongRunningMethod());

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", and the number {1}", s, iExecThread.ToString() ) );
}

答案 1 :(得分:0)

你必须等待;来自Calling Synchronous Methods Asynchronously

  

EndInvoke可能会阻塞调用线程,因为它在异步调用完成之前不会返回

用于执行阻止的机制可能类似于以下内容:

IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);

// wait for async invocation to complete
ar.AsyncWaitHandle.WaitOne()

必须调用EndInvoke(有关更多讨论,请参阅this question)。

如果您不想等待,则需要使用异步回调来执行EndInvoke

dlgt.BeginInvoke(3000, out iExecThread, ar => dlgt.EndInvoke(out iExecThread, ar), null);

执行此操作时,您将不知道异步调用的结果;您无法获得返回值,也不会知道对任何out参数进行了哪些更改(反直觉,BeginInvoke不会更改任何out个参数 at )。


据说,.NET从.NET 4开始获得了优秀的异步编程API;较新的模式结构更好,功能更强大,更易于使用(特别是在4.5中)。如果您有选项,则应该查看.NET 4's TPL.NET 4.5's TAP