当您调用异步方法时,它会返回一个
Task<T>
,其中 T
是结果的类型。
现在,您有两种方法来处理此任务。您可以使用 getter
.Result
等待任务完成并获取包装的值,也可以使用 await
,看起来它在做同样的事情。或者不是吗?
我试图找到这个问题的答案,并看到@Frank Fajardo 回复这样说:
await 异步解开任务结果 [...] 结果会阻塞 [...]
我不太确定@Frank Fajardo 在说什么。
await
不也阻止了Main()
的执行吗?
这是一个示例:请注意,
foo()
仅在barAsync()
返回的任务完成后(当使用await barAsync()
时)被调用。fooTask().Result
和
barAsync().Result
也是如此:using System;
using System.Threading;
using System.Threading.Tasks;
public class App
{
public static async Task Main(string[] args)
{
Console.WriteLine (await barAsync());
Console.WriteLine (foo());
Console.WriteLine (fooTask().Result);
Console.WriteLine (foo());
Console.WriteLine (barAsync().Result);
Console.WriteLine (foo());
}
public static Task<string> fooTask()
{
return Task.Run(() => {
Thread.Sleep(1000);
return "faz";
});
}
public static async Task<string> barAsync()
{
Thread.Sleep(5000);
return "baz";
}
public static string foo()
{
return "--- faz ---";
}
}
那么,有什么区别呢?使用
await
时哪个线程不会被阻塞?
.Wait()
会阻塞当前线程,直到任务完成。
await
不会阻塞当前线程。相反,当前执行流程(async
方法)被挂起,当任务完成时,流程将在完成任务的线程上恢复。在大多数情况下,完成线程是 ThreadPool
线程。完成线程是由异步方法的内部实现选择的。某些应用程序类型,例如 WinForms 和 WPF 应用程序,在主线程上配备了特定于应用程序的 ,它通过重新安排
await
延续来改变每个 await
的行为,通常将其重定向回UI 线程。控制台应用程序没有配备 SynchronizationContext
(并且不存在专门的内置实现)。由于主线程的终止会导致进程的终止,因此具有 async
Main
方法的控制台应用程序实际上会阻塞主线程,以防止进程终止。阻塞是通过
.GetAwaiter().GetResult()
执行的,这与 .Wait
类似,只是异常传播方式不同。