Task.Run(async () => await MethodAsync()).Result 和 MethodAsync().Result 之间有什么区别吗? [英] Is there any difference between Task.Run(async () => await MethodAsync()).Result and MethodAsync().Result?
问题描述
我需要实现一个不支持异步的第三方接口,特别是来自 automapper 的 IValueResolver.
I need to implement a third-party interface that doesn't support async, specifically IValueResolver from automapper.
我想知道这两段代码有什么区别?使用第一个而不是第二个有什么好处吗?我将在 MethodAsync() 上调用外部异步 API
I'm wondering what's the difference between these two pieces of code? Is there any advantage of using the first instead of the second? I will call an external async API on MethodAsync()
两者都锁定线程还是只锁定第二个?
Will both lock the thread or just the second?
1
var myValue = Task.Run(async () => await MethodAsync()).Result;
2
var myValue = MethodAsync().Result;
推荐答案
1)
var myValue = Task.Run(async () => await MethodAsync()).Result;
异步方法的同步部分 MethodAsync
将在线程池线程中运行.
The synchronous part of the asynchronous method MethodAsync
will run in a thread-pool thread.
2)
var myValue = MethodAsync().Result;
异步方法MethodAsync
的同步部分将在调用者的线程中运行.
The synchronous part of the asynchronous method MethodAsync
will run in the caller's thread.
现在你可能会问,异步方法的同步部分是什么?
同步部分是异步方法中第一个 await
之前的所有内容.
The synchronous part is everything before the first await
inside the asynchronous method.
更准确地说:同步部分是未完成的可等待对象的第一个 await
之前的所有内容.
More precisely: The synchronous part is everything before the first await
of a non-completed awaitable.
通常同步部分很小,但当我们谈论未知的外部 API 时,我们不能 100% 确定.
Usually the synchronous part is minuscule, but when we talk about an unknown external API we cannot be 100% sure.
在调用者的线程或线程池线程中运行阻塞代码之间的区别可能并不那么重要.在这两种情况下,调用者的线程将在异步调用的整个持续时间内被阻塞.第一种方法 (Task.Run
) 有什么优势吗?通常添加Task.Run
来解决死锁问题,当await
和Wait/Result
混合时很容易发生.在您的情况下,如果您出于某种原因在内部使用 await
,或者外部 API 在内部使用 await
而没有 ConfigureAwait(false)
,则可能会发生此类问题.在这种情况下,您会立即注意到它,并且可能会修复它.所以主动使用 Task.Run
的好处是安心.缺点是使用线程池线程来运行该方法的同步部分.在大多数情况下,这部分非常小,以微秒为单位,因此如果您遵循简单的路径,您应该不会感到内疚.
The difference between running blocking code in the caller's thread or in a thread-pool thread is probably not that important. In both cases the caller's thread will be blocked for the whole duration of the async call. Does the first approach (Task.Run
) offers any advantage? Usually the Task.Run
is added to solve problems of deadlocks, that can easily occur when await
and Wait/Result
are mixed. In your case such problems could occur if you use await
internally for some reason, or the external API uses await
internally without ConfigureAwait(false)
. In that case you'll notice it immediately and you'll probably fix it. So the advantage of using Task.Run
proactively is peace of mind. The disadvantage is that a thread-pool thread is utilized for running the synchronous part of the method. In most cases this part is very small, measured in μsec, so you shouldn't feel guilty if you follow the easy path.
更新:这是第一种方法的一个例子,它也演示了外部方法的同步和异步部分:
Update: Here is an example of the first approach, that also demonstrates the synchronous and the asynchronous part of the external method:
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
是多余的,因为外部库遵循了使用 ConfigureAwait(false)
等待的良好实践.
In this case the prophilactic use of Task.Run
is redundant because the external library follows the good practice of awaiting with ConfigureAwait(false)
.
这是第二种方法的示例:
Here is an example of the second approach:
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}";
}
这段代码死锁了.如果直接请求Result
,而没有Task.Run
,即使是外部库中单个未配置的顶级await
也会导致死锁>.
This code deadlocks. Even a single non-configured top-level await
inside the external library will cause a deadlock, if you request the Result
directly, without Task.Run
.
这篇关于Task.Run(async () => await MethodAsync()).Result 和 MethodAsync().Result 之间有什么区别吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!