【问题标题】:Begin end asynchronuos method call开始结束异步方法调用
【发布时间】:2014-05-17 03:56:57
【问题描述】:

这是来自 Microsoft 的代码 sn-p。 我对异步方法调用有疑问。

因为我们在 Begin-invoke 之后调用 end.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() ) );
}

【问题讨论】:

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


    【解决方案1】:

    如果异步方法没有完成会发生什么 调用 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 线程上awaitawait 之后的代码也会在 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() ) );
    }
    

    【讨论】:

    • 我正在使用 .Net 3.5。所以异步背后的所有东西。 call 是,它将在一个新线程中开始,我们可以在调用 endinvoke 方法之前做一些工作。我的要求是打电话然后离开,之后我什么都不关心,其他一切都将由 assync 方法处理。我不必对回调做任何事情
    • 在您的第一个示例中,您告诉MethodDelegate.BeginInvoke 在后台线程上执行,这反过来又告诉this.LongRunningMethod 开始在后台线程中运行;还有很多额外的工作要做。
    【解决方案2】:

    你必须等待;来自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 参数 /em>)。


    话虽如此,.NET 从 .NET 4 开始就获得了出色的异步编程 API;较新的模式结构更好,功能更强大,更易于使用(尤其是在 4.5 中)。如果你有选择,你应该看看.NET 4's TPL.NET 4.5's TAP

    【讨论】:

    • 所以异步背后的所有东西。 call 是,它将在一个新线程中开始,我们可以在调用 endinvoke 方法之前做一些工作。我的要求是调用并离开之后我不关心任何事情,其他所有事情都将由 assync 方法处理。
    • 我添加了一个不等待的例子。
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 2017-10-16
    • 1970-01-01
    相关资源
    最近更新 更多