在我的代码示例中,主线程在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");
});
}
执行此代码的结果
主要开始
task1开始
task1结束
主要2 主3 task2开始
主要目的
task2结束
如何更改“主要结束”位于列表末尾的代码。
答案 0 :(得分:2)
在getTask2
{} {}}中,您只需启动Task
另一个Task
。所以当你await
Task
它完成开始内部任务后它将继续执行,而不是当内部任务完成时
在这种情况下,你根本没有理由创建一个新任务,只是为了首先开始一个新任务;你应该只使用第一种方法中使用的方法。
当然,如果由于某种原因,你做需要创建一个新的Task
只是为了开始一个新任务,那么你需要让内部Task
出来确保主方法仅在内部 Task
完成后继续执行。创建Unwrap
的{{1}}方法在逻辑上等同于另一个Task
的{{1}} Task
:
Result
但你甚至不需要这样做。如果给出一个产生Task
的lambda,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.Run
再一次,这是假设只需启动异步操作需要卸载到另一个线程,这应该非常罕见。通常这意味着该异步方法中存在一个错误,因为它在首先给你Task
之前不应该进行长时间的同步工作,但有时该方法将来自一个你无法控制的外部图书馆,所以这是你唯一的选择。
答案 1 :(得分:1)
您正在使用的Task
的构造函数重载具有以下签名:
public Task(Action action)
虽然您可以将以下表达式分配给Action
类型的变量:
async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
}
此操作将指向同步函数,该函数将在达到await
await Task.Delay(100);
时同步完成(尽管“操作”的其余部分将以异步方式继续)。因此,就Task
对象而言,一旦达到Action
,就会完成此await
的执行。这意味着await
中的await task2;
将在该点异步继续,这解释了为什么在“task2 end”之前打印“Main end”的原因。
基本上,Task
的构造函数不支持异步操作,只支持同步操作。
要解决此问题,您需要使用了解异步操作的方法来启动任务。异步操作如下所示:Func<Task>
。
Task.Run
方法支持异步操作,因为它具有以下重载:
public static Task Run(Func<Task> function)
因此,要修复代码,请将return new Task(...
更改为return Task.Run(...
,然后不要在返回的任务上调用Start
方法,因为Task.Run
将创建{{1}已经开始了。
如果你想延迟执行第二个“任务”,那么我建议让Task
方法返回getTask2
(异步操作)而不是Func<Task>
,如下所示:
Task
然后在需要private Func<Task> getTask2()
{
return async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
};
}
方法时运行此类异步操作:
Run
答案 2 :(得分:0)
new Task(
本身不能与异步函数一起使用。您正在创建Task<Task>
,需要在等待内部任务之前调用Unwrap()
。
private Task<Task> getTask2()
{
return new Task(async () =>
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
});
}
var task2 = getTask2();
Console.WriteLine("Main 3");
task2.Start();
await task2.Unwrap();
答案 3 :(得分:-1)
您的代码中有错误。您尚未使用关键字getTask2
标记async
方法,而是await
其结果。即使您在方法中使用async
委托,如果要成功等待,也必须使用async
关键字。
以下是关于如何实现理想结果的想法。
public async Task Run()
{
Console.WriteLine("Main start");
await getTask1();
await getTask2();
Console.WriteLine("Main end");
}
public async Task AlternateRun()
{
Console.WriteLine("Main start");
List<Task> task_list = new List<Task>();
task_list.Add(getTask1());
task_list.Add(getTask2());
var task_result = Task.WhenAll(task_list);
task_result.Wait();
Console.WriteLine("Main end");
}
private async Task getTask1()
{
Console.WriteLine("task1 start");
await Task.Delay(100);
Console.WriteLine("task1 end");
}
private async Task getTask2()
{
Console.WriteLine("task2 start");
await Task.Delay(100);
Console.WriteLine("task2 end");
}
我还添加了一个AlternateRun方法,该方法将演示等待多个任务的替代方式。如果您需要按顺序完成任务,请考虑使用ContinueWith
扩展方法。
请注意,我还删除了您的task2.Start()
声明。这已由await
关键字隐含。
希望这有帮助。