Task.Run(async () => await MethodAsync()).Result 和 MethodAsync().Result 之间有什么区别吗? [英] Is there any difference between Task.Run(async () => await MethodAsync()).Result and MethodAsync().Result?

查看:40
本文介绍了Task.Run(async () => await MethodAsync()).Result 和 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来解决死锁问题,当awaitWait/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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆