代码之家  ›  专栏  ›  技术社区  ›  Dave

如何在C中调用从同步方法返回void的异步方法,并确保异步方法已完成?

  •  0
  • Dave  · 技术社区  · 7 年前

    我已经搜索了StackOverflow,但没有找到我的具体情况的确切答案。 我有一个方法:

    public async Task InitializeMachine()
    {
        await DoSomeWork1();
        // other stuff
        await DoSomeWork2();
        // other stuff
    }
    

    请注意,它返回的签名是 Task Task<T> . 这样重写所有的方法是很困难的(如果不是不可能的话)。 我想从同步方法调用这个方法,并让它等待InitializeMachine方法完全完成。同样,很难将其更改为异步方法(下面我将为感兴趣的人描述原因)。 我查看了一些相关问题和参考资料,例如:

    https://msdn.microsoft.com/en-us/magazine/mt238404.aspx

    await works but calling task.Result hangs/deadlocks

    How to call asynchronous method from synchronous method in C#?

    答案似乎很旧(也许有新的更好的方法?)至少在许多情况下,它们似乎依赖于异步方法返回 任务(<);T> ,而不仅仅是 任务 . 我有

    void Initialize()
    {
        //InitializeMachine(); // Perfectly legal, but will return at first await
         //return Task.Run(() => InitializeMachine()).GetAwaiter().GetResult();  // can't get this to compile. My typo? Or because it's Task not Task<T> ? This is the "Thread Pool Hack" in first reference above by Stephen Cleary
         var task = Task.Run(() => InitializeMachine()); // these 2 lines work!
            task.Wait();  // but see heated argument in 2nd reference in the answer by Herman Schoenfeld. Is it safe?
            Task task = Task.Run(async () => await InitializeMachine()); // also works. Comes from 3rd reference by author "Tohid"
    
    }
    

    有人能告诉我应该使用哪种方法吗?为什么?正如我所说,我试图做这项研究,但发现自己对所有关于为什么会出现潜在僵局和其他问题的论点都有点不知所措。所有的分歧使我更加困惑。到2018年肯定会有一个明确的方法?

    谢谢Dave

    P、 对于那些关心的人,我正在玩SMC国家机器库。请参见: https://sourceforge.net/projects/smc/ 简而言之,状态机代码是从文本文件自动生成的。但生成的代码是同步方法。是的,我可以破解生成的代码(但它会被覆盖),或者重新思考整个问题(也许InitializeMachine不应该是异步的),但我的问题仍然存在。在我看来,有时同步方法需要调用异步方法,它们应该等到异步方法完成!

    2 回复  |  直到 7 年前
        1
  •  2
  •   Camilo Terevinto Chase R Lewis    7 年前

    您应该使用以下选项:

    InitializeMachine().GetAwaiter().GetResult();
    

    这将确保在 InitializeMachine 未包装到 AggregateException . 请注意 return 不需要语句,因为您没有返回任何内容( void 方法)。

    编辑
    由于您使用的是WPF,因此最好始终保持异步模式:

    public async void InitializeMachineAsync()
    {
        await DoSomeWork1().ConfigureAwait(false);
        await DoSomeWork2().ConfigureAwait(false);
    }
    

    InitializeMachineAsync 可以是任何事件(如 Window_Load )

        2
  •  -1
  •   Z .    7 年前

    最简单的方法是

    InitializeMachine().Wait();
    

    关于异常处理有一些注意事项