Dav*_*eli 3 c# console-application async-await c#-7.1
我正在运行以下代码(C#7.1控制台应用程序),我无法理解为什么行为上的差异.
如果我等待常规的异步方法调用或Task.Run - 它按预期工作(即应用程序不会立即返回).但是,如果我使用Task.Factory.StartNew - 它将立即返回,而不会实际运行代码.
奇怪的是 - 如果我使用StartNew但是在方法内部删除await,它将不会立即返回...
问题:立即返回:
static async Task Main(string[] args)
{
await Task.Factory.StartNew(DisplayCurrentInfo);
}
static async Task DisplayCurrentInfo()
{
await WaitAndApologize();
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Thread.Sleep(3000);
}
Run Code Online (Sandbox Code Playgroud)
即 - 我不会看到打印到控制台的任何内容,控制台已经关闭.
没问题:这不会立即返回:
static async Task Main(string[] args)
{
await DisplayCurrentInfo(); // or await Task.Run(DisplayCurrentInfo);
}
static async Task DisplayCurrentInfo()
{
await WaitAndApologize();
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Thread.Sleep(3000);
}
Run Code Online (Sandbox Code Playgroud)
奇怪:这也不会立即返回:
static async Task Main(string[] args)
{
await Task.Factory.StartNew(DisplayCurrentInfo);
}
static async Task DisplayCurrentInfo()
{
WaitAndApologize();
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Thread.Sleep(3000);
}
Run Code Online (Sandbox Code Playgroud)
WaitAndApologize:
static async Task WaitAndApologize()
{
// Task.Delay is a placeholder for actual work.
await Task.Delay(2000);
// Task.Delay delays the following line by two seconds.
Console.WriteLine("\nSorry for the delay. . . .\n");
}
Run Code Online (Sandbox Code Playgroud)
如果您使用Task.Factory.StartNew(MethodThatReturnsTask),则返回a Task<Task<T>>或Task<Task>取决于该方法是否返回通用任务.
最终结果是你有2个任务:
Task.Factory.StartNew产生一个调用的任务MethodThatReturnsTask,让我们称这个任务为"任务A"MethodThatReturnsTask在你的情况下返回一个Task,让我们调用这个"任务B",这意味着使用了StartNew处理它的重载,最终的结果是你得到了一个包装任务B的任务A.要"正确"等待这些任务需要2等待,而不是1.你的单一等待只是等待任务A,这意味着当它返回时,任务B仍在执行等待完成.
要天真地回答你的问题,请使用2等待:
await await Task.Factory.StartNew(DisplayCurrentInfo);
Run Code Online (Sandbox Code Playgroud)
但是,为什么你需要生成一个任务只是为了启动另一个异步方法,这是值得怀疑的.相反,你最好使用第二种语法,只需等待方法:
await DisplayCurrentInfo();
Run Code Online (Sandbox Code Playgroud)
意见如下:一般来说,一旦你开始编写异步代码,Task.Factory.StartNew当你需要生成一个线程(或类似的东西)来调用与某些东西不同步的东西时,应该保留使用或者它的任何兄弟方法.其他.如果您不需要这种特殊模式,最好不要使用它.