如果从未等待过 RunAsync 可以吗?
这取决于。从JoinableTaskFactory 的角度来看是可以的。所有必要的延续都将继续——只是你的调用方法不会等待它完成,如果你选择这样做,这就是不等待它的全部意义。
但总的来说,它可能不适合您的应用。考虑您的异步工作正在保存文件(或通过网络传输某些内容)并且用户关闭您的应用程序的情况。您不希望应用程序在关闭之前等待它完成吗?正如@GrzegorzSmulko 在他的回答中所说,JoinableTaskFactory 规定 a pattern 用于阻止关闭(或处置您的对象)以确保异步工作完成。
如果您在托管 CLR 并在退出前将其关闭的应用程序中跟踪您的异步工作,还有另一个原因:您不希望托管线程在 AppDomain 完成时运行任意事情,或者您会发现您的应用程序在关机时崩溃。但是,当您拥有纯托管应用程序时,这不是问题,因为它只是退出而不关闭 CLR。它不会崩溃,但仍会放弃任何半途而废的工作。
在您使用JoinableTaskFactory 的任何应用程序中,上述所有内容都是正确的。如果您碰巧在 Visual Studio 中使用它(我在这里一般是为更广泛的受众发言……我知道您的问题特别提到了 VS),那么规则的压力就会更大。您应该按照该部分的规定跟踪所有您的异步工作。你不应该有任何“一劳永逸”的工作。
FileAndForget 扩展方法实际上是供 Microsoft 内部使用的,因为它会将错误发送到我们的遥测服务器。如果你真的想忘记一些东西,你可以使用.Forget() 扩展方法。但是请记住,您应该只在使用AsyncPackage.JoinableTaskFactory 实例或另一个跟踪您的异步工作以进行处置的实例安排工作之后使用它。不要在ThreadHelper.JoinableTaskFactory 上使用它,因为它不会跟踪异步和被遗忘的工作。例如,不要这样做:
ThreadHelper.JoinableTaskFactory.RunAsync(async () => { /* something async */ }).Forget();
上面的问题是异步工作不会被跟踪,因此不会阻塞关机。您应该改为这样做:
myAsyncPackage.JoinableTaskFactory.RunAsync(async () => { /* something async */ }).Forget();
或者更好:只需 await 调用,在这种情况下,您几乎可以使用任何 JTF 实例:
await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { /* something async */ });
但是,如果您处于可以使用 await 的上下文中,则通常根本不需要 JoinableTaskFactory.RunAsync,因为如果您可以在委托本身中等待代码。一些不常见的情况可能需要您仍然使用 JoinableTaskCollection 跟踪异步工作,您可能希望在其中使用 await someJtf.RunAsync,但通常您可以在自然等待工作的地方放弃 JTF 使用。