我在不同地方读过关于ConfigureAwait的文章(包括一些问题),下面是我的结论:
.ConfigureAwait(true)。否则,由于另一个线程访问UI元素,将出现InvalidOperationException。我的问题是:
发布于 2020-07-02 13:27:58
为了更直接地回答你的问题:
ConfigureAwait(true):在等待程序运行之前,在同一个线程上运行其余的代码。
不一定是同一个线程,而是相同的同步上下文。同步上下文可以决定如何运行代码。在UI应用程序中,它将是同一个线程。在ASP.NET中,它可能不是同一个线程,但是您将像以前一样拥有可用的HttpContext。
ConfigureAwait(false):在等待的代码运行的同一个线程上运行其余的代码。
这不对。ConfigureAwait(false)告诉它它不需要上下文,所以代码可以在任何地方运行。它可能是运行它的任何线程。
如果等待后面跟着访问UI的代码,则任务应附加
.ConfigureAwait(true)。否则,由于另一个线程访问UI元素,将出现InvalidOperationException。
“应该附加.ConfigureAwait(true)”是不正确的。ConfigureAwait(true)是默认的。所以如果这是你想要的,你不需要指定它。
返回同步上下文可能需要时间,因为它可能需要等待其他东西才能完成运行。实际上,这种情况很少发生,或者等待时间太短,以至于你永远不会注意到这一点。
您可以使用ConfigureAwait(false),但我建议您不要使用,原因如下:
ConfigureAwait(false),则该延续可以在任何线程上运行,因此,如果要访问非线程安全对象,则可能会出现问题。出现这些问题并不常见,但这是可能发生的。ConfigureAwait(false)很容易被发现(它的方法可能不同于抛出异常的地方),并且您/他们知道它会做什么。我发现完全不使用ConfigureAwait(false)会更容易(除了在库中)。用ConfigureAwait常见问题中的Stephen (微软雇员)的话来说
在编写应用程序时,通常需要默认行为(这就是为什么它是默认行为)。
编辑:我已经写了一篇关于这个主题的文章:.NET:不要使用ConfigureAwait(假)
发布于 2020-07-01 17:05:45
如果可用的工作线程不多,并且需要等待的线程总是繁忙的话,ConfigureAwait(false)可能会提高性能。
在不需要返回同一个SynchronizationContext (通常使用线程链接)的地方,推荐使用SynchronizationContext,特别是在内部等待的库中:https://medium.com/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f。
当您需要相同的上下文时,需要ConfigureAwait(true) (这是默认的),但在某些情况下也可能导致死锁。
请考虑以下代码:
void Main()
{
// creating a windows form attaches a synchronization context to the current thread
new System.Windows.Forms.Form();
var task = DoSth();
Console.WriteLine(task.Result);
}
async Task<int> DoSth()
{
await Task.Delay(1000);
return 1;
}在本例中,由于没有等待任务DoSth,主UI线程被等待task.Result阻塞-同时DoSth被阻塞,因为它想在延迟后返回到UI线程。这将导致死锁,这段代码将永远不会执行到最后。添加.ConfigureAwait(false)解决了这种情况下的问题。
发布于 2020-07-01 19:03:27
在应用程序代码中使用ConfigureAwait(false)通常不会以任何有意义的方式提高应用程序的性能,因为在应用程序代码中通常不会在循环中使用await。例如,假设您的应用程序有一个按钮,每次用户单击该按钮时都会启动一个异步操作,而异步操作包括一个await。通过在此.ConfigureAwait(false)之后键入22个字符await,您已经损失了您生命中的相应时间,您可以希望从10个用户中节省下来,这些用户每分钟单击该按钮一次,每天8小时,持续20年(总计35,000,000次上下文切换=某些秒的CPU处理时间)。
在考虑是否可以安全地包含此配置(取决于是否继续包含与UI相关的代码)、每次必须维护/修改代码时重新确认之前的评估所需的时间、以及在评估错误时调试所损失的时间之前,请考虑到这一点。
另一方面,如果Button_Click处理程序包含如下代码:
private async void Button_Click(object sender, EventArgs e)
{
var client = new WebClient();
using var stream = await client.OpenReadTaskAsync("someUrl");
var buffer = new byte[1024];
while ((await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
//...
}
}...then无论如何都要花费额外的时间来执行ReadAsync任务。还要考虑通过将流读取部分移动到一个单独的异步方法来重构代码,这样您就可以安全地访问Button_Click处理程序中任何地方的UI元素,而不会因为不属于应用程序这一层的技术细节而分心。
https://stackoverflow.com/questions/62681749
复制相似问题