C# 使用ConfigureWait(false)或Task.Run可避免阻塞UI线程

C# 使用ConfigureWait(false)或Task.Run可避免阻塞UI线程,c#,xamarin,.net-core,async-await,C#,Xamarin,.net Core,Async Await,我试图找出哪种方法更好,比如说我们有一个按钮,用户点击后我们执行1。使用httpClient 2.一些繁重的同步工作人员喜欢计算和将数据保存到数据库 就像这样: button1.Click += async(sender, e) => { bool a = await Task.Run(async () => { return await MyTask1();}); } async Task<bool> MyTask1() { await new Htt

我试图找出哪种方法更好,比如说我们有一个按钮,用户点击后我们执行1。使用
httpClient
2.一些繁重的同步工作人员喜欢计算和将数据保存到数据库

就像这样:

button1.Click += async(sender, e) => 
{
    bool a = await Task.Run(async () => { return await MyTask1();});
}
async Task<bool> MyTask1()
{
    await new HttpClient().GetAsync("https://www.webpage.com");
    DoHeavyStuffFor5minutes();
    return true;
}
button1.Click+=async(发送方,e)=>
{
boola=await Task.Run(异步()=>{return await MyTask1();});
}
异步任务MyTask1()
{
等待新的HttpClient().GetAsync(“https://www.webpage.com");
DoheavyStuffor5分钟();
返回true;
}
button2.Click+=async(发送方,e)=>
{
bool a=等待MyTask2();
}
异步任务MyTask2()
{
等待新的HttpClient().GetAsync(“https://www.webpage.com“”。配置等待(错误);
DoheavyStuffor5分钟();
}
据我所知,
GetAsync
不会阻止我的UI线程,因为它下面使用了一种方法,使它在不同的线程上运行,可能是
Task.Run
或任何其他允许它的方法。 但是
DoHeavyStuffor5mins
将阻止我的UI,因为它将在调用方
SynchornizationContext
上被调用。
因此,我了解到,使用
ConfigureAwait(false)
将使
GetAsync
之后的代码不会在与调用方相同的SynchornizationContext上运行。我的问题是,第一种还是第二种方法更好?

没有必要在后台线程上使用任务执行
HttpClient.GetAsync
。运行
,因为HTTP请求本质上是真正异步的,所以在这种情况下,第二种方法比第一种方法更好

GetAsync
返回的
Task
最终完成时,如果您通过调用
ConfigureAwait(false)
选择不捕获上下文,则剩余的任务或
MyTask2()
将在线程池线程上执行

但是请注意,
ConfigureAwait(false)
并不保证回调或remainer不会在所有情况下都在原始上下文中运行

来自Stephen Toub的:

ConfigureAwait(false)是否保证回调不会在原始上下文中运行?

“不。它保证它不会排队回到原始上下文…但这并不意味着
wait任务后的代码。configurewait(false)
将不再在原始上下文中运行。这是因为等待已完成的等待表只需同步运行
wait
而不是强制任何内容重新排队。因此,如果您
wait
在等待时已完成的任务,无论您是否使用
ConfigureAwait(false)
,紧随其后的代码将继续在当前线程上执行,无论上下文是否仍然是当前的。”

因此,您可能希望使用
任务将
doheavyStuffor5mins
卸载到后台线程。为了安全起见,请运行
。至少在一般情况下


还请注意,名为*Async并返回
任务
任务
的方法可能仍会阻止调用线程,具体取决于其实现。通常,这可能是使用第一种方法在后台线程上调用这两个方法以避免阻塞UI线程的原因。但是,如果您使用了实现良好的API,例如
HttpClient
,那么这并不是一个问题。

为什么“数据库上的繁重内容”不是异步的?编辑后的问题可以避免此类问题confusion@whd这一点仍然存在。如果操作花费时间将内容保存到数据库,为什么不异步执行此操作?@Servy假设它是一个不提供异步方法的库中的方法。但在这种情况下,什么更好仍然是一个有效的问题
wait someasymethod();Task.Run(()=>{SomeHeavyMethod();};
等待someasynchmethod().ConfigureAwait(false);SomeHeavyMethod();
第一种方法更好。至少在一般情况下,您可以阅读我支持
Task.Run
“的参数。”-是的。特别是,某些移动平台上的
HttpClient
可能会返回(缓存)结果同步。
button2.Click += async(sender, e) => 
{
    bool a = await MyTask2();
}
async Task<bool> MyTask2()
{
    await new HttpClient().GetAsync("https://www.webpage.com").ConfigureAwait(false);
    DoHeavyStuffFor5minutes();
}