1)
var myValue = Task.Run(async () => await MethodAsync()).Result;
异步方法的同步部分MethodAsync
将在线程池线程中运行。
2)
var myValue = MethodAsync().Result;
异步方法的同步部分MethodAsync
将在调用者的线程中运行。
现在你可能会问,异步方法的同步部分是什么?
同步部分是第一个之前的所有内容await
在异步方法内部。
更准确地说:同步部分是第一个之前的所有内容await
未完成的等待。
通常同步部分很小,但是当我们谈论未知的外部 API 时,我们不能 100% 确定。
在调用者线程或线程池线程中运行阻塞代码之间的区别可能并不那么重要。在这两种情况下,调用者的线程将在异步调用的整个持续时间内被阻塞。第一种方法是否(Task.Run
)有什么优势吗?通常是Task.Run
添加解决死锁问题,这很容易发生在await
and Wait/Result
是混合的。在您的情况下,如果您使用,可能会出现此类问题await
由于某种原因在内部,或者外部 API 使用await
内部没有ConfigureAwait(false)
。在这种情况下,您会立即注意到它,并且可能会修复它。所以使用的好处是Task.Run
主动就是安心。缺点是使用线程池线程来运行该方法的同步部分。在大多数情况下,这部分非常小,以微秒为单位测量,因此如果您遵循简单的路径,您不应该感到内疚。
Update:这是第一种方法的示例,它还演示了外部方法的同步和异步部分:
private void Button1_Click(object sender, EventArgs e)
{
this.Text = YourMethod();
}
public static int YourMethod()
{
return Task.Run(async () => await ExternalMethodAsync()).Result;
}
public static async Task<string> ExternalMethodAsync()
{
Thread.Sleep(500); // Synchronous part
await Task.Delay(500).ConfigureAwait(false); // Asynchronous part
return $"Time: {DateTime.Now:HH:mm:ss.fff}";
}
在这种情况下,预防性使用Task.Run
是多余的,因为外部库遵循 waiting with 的良好实践ConfigureAwait(false)
.
这是第二种方法的示例:
public static int YourMethod()
{
return ExternalMethodAsync().Result;
}
public static async Task<string> ExternalMethodAsync()
{
Thread.Sleep(500); // Synchronous part
await Task.Delay(500); // Asynchronous part
return $"Time: {DateTime.Now:HH:mm:ss.fff}";
}
这段代码出现死锁。即使是单个未配置的顶级await
如果您请求在外部库内部会导致死锁Result
直接地,无需Task.Run
.