在我的代码示例中,task2 完成时主线程不会等待。
public async Task Run()
{
Console.WriteLine("Main start");
await getTask1();
Console.WriteLine("Main 2");
var task2 = getTask2();
await Task.Delay(1);
Console.WriteLine("Main 3");
task2.Start();
await task2;
Console.WriteLine("Main end");
}
private async Task getTask1()
{
Console.WriteLine("task1 start");
await Task.Delay(100);
Console.WriteLine("task1 end");
}
private Task getTask2()
{
return new Task(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
}
这段代码的执行结果是
Main start
task1 start
task1 end
Main 2
Main 3
task2 start
Main end
task2 end
如何更改“Main end”位于列表末尾的代码。
最佳答案
在 getTask2
中,您正在启动一个Task
,而该任务又启动另一个Task
。因此,当您等待
该任务
时,它会在完成启动内部任务后立即继续执行,而不是当该内部任务启动时>完成。
在这种情况下,您根本没有理由创建一个新任务只是为了首先开始一个新任务;您应该只使用第一种方法中使用的方法。
当然,如果由于某种原因,您确实需要创建一个新的Task
只是为了开始一个新任务,那么您需要获取内部任务
并确保 main 方法仅在内部 任务
完成后继续执行。有一个 Unwrap
方法来创建一个 Task
,该任务在逻辑上等同于一个 Task
,而该 Task
是另一个任务的 Result
任务
:
private Task getTask2()
{
Task<Task> task = new Task<Task>(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
task.Start();
return task.Unwrap();
}
但你甚至不需要这样做。如果给定一个生成 Task
的 lambda,Task.Run
将自动为您解包该值:
private Task getTask2()
{
return Task.Run(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
}
再次强调,这一切都假设只是启动异步操作就需要卸载到另一个线程,这种情况应该非常罕见。通常这意味着该异步方法存在一个错误,因为在首先向您提供其 Task
之前,它不应该执行长时间运行的同步工作,但有时该方法来自外部您无法控制的库,因此这将是您唯一的选择。
关于c# - 如何等待稍后开始的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39415527/