我有这个代码:
var task = Task.Factory.StartNew(() => service.StartAsync(ct), ct);
但我想知道它是否应该是这样的:
var task = Task.Factory.StartNew(async () => await service.StartAsync(ct), ct).Unwrap();
启动异步服务的第一个是否正确?还是第二个更好?
考虑返回的任务类型,第一个产生Task<Task<int>>
,而第二个产生Task<int>
。因此,实际上第一个是表示内部任务启动的Task
,而第二个解包表示表示服务启动的内部方法返回的Task
。最后,您还可以Unwrap
第一个并获得相同的效果,而无需async/await
,这在这里是不必要的。在这种情况下,这些都没有真正涵盖对StartNew
的需求,只是查看您查看的返回类型。
请考虑以下代码:
public class AsyncTesting
{
public void StartServiceTest()
{
Task<Task<int>> tsk1 = Task.Factory.StartNew(() => StartAsync());
Task<int> tsk2 = Task.Factory.StartNew(() => StartAsync()).Unwrap();
Task<int> tsk3 = Task.Factory.StartNew(async () => await StartAsync()).Unwrap();
}
public Task<int> StartAsync() => Task.Delay(2500).ContinueWith(tsk => 1);
}
不Unwrap
的方法返回一个Task
,该表示启动内部Task
而不是它所做的工作。
正如JSteward在他们的回答中所解释的那样,第一行代码是错误的。它不会执行您希望它执行的操作:
Task<Task> task = Task.Factory.StartNew(() => service.StartAsync(ct), ct); // Buggy
第二行具有正确的行为,但不是因为异步/等待。可以安全地省略异步/等待。使它正确的是Unwrap
。不过,它仍然存在问题,因为它违反了关于不通过TaskScheduler
就不创建任务的准则 CA2008 .
解决问题的最佳方法是使用Task.Run
方法:
Task task = Task.Run(() => service.StartAsync(ct), ct); // Correct
您可以在Stephen Toub的这篇文章中阅读有关Task.Run
和Task.Factory.StartNew
之间的差异。