简体   繁体   English

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

[英]How do I call asynchronous method returning void from synchronous method in C# and be sure async method is finished?

I have searched StackOverflow and not found a definitive answer to my particular situation. 我搜索了StackOverflow,但没有找到针对我的特定情况的明确答案。 I have a method: 我有一个方法:

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

Notice the signature it returns is Task , not Task<T> . 请注意,它返回的签名是Task ,而不是Task<T> It would be difficult (if not impossible to rewrite all the methods like this. I would like to call this method from a synchronous method AND have it wait for the InitializeMachine method to completely finish. Again, it would be hard to change it into an async method (I'll describe why below for those interested). I have looked at some related questions and references such as: 这将很困难(如果不是不可能重写所有这样的方法。我想从同步方法中调用此方法,并让它等待InitializeMachine方法完全完成。同样,很难将其更改为异步方法(下面我将为感兴趣的人介绍为什么)。我研究了一些相关的问题和参考,例如:

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

await works but calling task.Result hangs/deadlocks and 等待工作但调用task.Result挂起/死锁

How to call asynchronous method from synchronous method in C#? 如何在C#中从同步方法调用异步方法?

The answers seem to be old (perhaps there is a newer better way?) and at least in many cases, they seem to depend on the async method returning Task<T> , not just Task . 答案似乎很旧(也许有一种更好的新方法?),至少在许多情况下,它们似乎取决于返回Task<T>的异步方法,而不仅仅是Task I have 我有

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"

}

Can someone tell me which method I should be using and why? 有人可以告诉我应该使用哪种方法,为什么? As I said, I tried to do the research but found myself a little lost on all the arguments as to why there could be a potential deadlock and other problems. 就像我说的那样,我尝试进行研究,但是发现自己对为什么存在潜在的僵局和其他问题的所有争论都有些失落。 Adding to my confusion was all the disagreements. 所有的分歧加剧了我的困惑。 Surely by 2018 there is a definitive way? 当然,到2018年有确定的方法吗?

Thanks, Dave 谢谢戴夫

PS For those who care, I'm playing with the SMC state machine library. PS对于那些在乎的人,我正在使用SMC状态机库。 See: https://sourceforge.net/projects/smc/ Briefly, state machine code is automatically generated from a text file. 参见: https : //sourceforge.net/projects/smc/简要地说,状态机代码是从文本文件自动生成的。 BUT the code generated is synchronous methods. 但是生成的代码是同步方法。 Yes, I could hack the generated code (but it will get overwritten) or rethink the entire problem (perhaps InitializeMachine should be not by asynch), but my question would remain nonetheless. 是的,我可以破解生成的代码(但是它将被覆盖)或重新考虑整个问题(也许InitializeMachine不应该通过异步发送),但是我的问题仍然存在。 It seems to me there are times where synchronous methods need to call async ones and they should wait until the async method is complete! 在我看来,有时候同步方法需要调用异步方法,它们应该等到异步方法完成!

You should be using this: 您应该使用此:

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

This will ensure that any exception raised at InitializeMachine is not wrapped into an AggregateException . 这将确保在InitializeMachine引发的任何异常都不会包装到AggregateException Note that the return statement is not needed since you aren't returning anything ( void method). 请注意,不需要return语句,因为您不返回任何内容( void方法)。

Edit 编辑
Since you are using WPF, it would be better if you just kept the async-all-the-way-down pattern: 由于您使用的是WPF,所以最好保持异步所有模式:

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

InitializeMachineAsync can be any event (like Window_Load ) InitializeMachineAsync可以是任何事件(例如Window_Load

the simplest thing to do is 最简单的事情是

InitializeMachine().Wait();

there are some considerations around exception handling 关于异常处理有一些注意事项

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM