JoinableTaskFactory.RunAsync的正确用法是什么?

时间:2018-04-30 21:43:41

标签: c# multithreading asynchronous

我在线搜索但关于ThreadHelper.JoinableTaskFactory.RunAsync

的信息非常少

如果我有以下代码,则Test1会在MainThread上运行:

public bool Test1()
{
    // Do something here
    ThreadHelper.JoinableTaskFactory.RunAsync(this.Test2);
    // Do something else
    return false;
}

private async Task Test2()
{
    await TaskScheduler.Default;
    // do something here    
    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
    // do something here
}

如果从未等待RunAsync,可以吗?如果Test1Test2完成运行之前返回会发生什么?

2 个答案:

答案 0 :(得分:1)

根据Threading Cookbook for Visual Studio,您应该将ThreadHelper.JoinableTaskFactory.RunAsync()FileAndForget()一起使用。

潜在的问题是,FileAndForget()在VS2015中不可用,但仅在VS2017 +中可用。

  

如果从未等待过RunAsync,可以吗?

我认为不行,你应该使用FileAndForget。但是,我真的不知道该为VS2015做些什么。

  

如果Test1Test2完成运行之前返回会发生什么?

这应该很容易测试以确保。我假设Test2稍后会完成"But you also should be sure your async work finishes before your object claims to be disposed."

答案 1 :(得分:1)

  

如果从未等待过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实例:

等待ThreadHelper.JoinableTaskFactory.RunAsync(async()=> {/ *异步* /});