C# 异步函数的调用结果是否会无限期地导致阻塞?

C# 异步函数的调用结果是否会无限期地导致阻塞?,c#,.net,async-await,task,c#-5.0,C#,.net,Async Await,Task,C# 5.0,我刚接触C#有着丰富的java背景,但仍在试图弄清楚Wait和async到底是如何工作的,以下是让我非常困惑的地方: 假设我有这样一个函数(下面的黑客代码仅用于实验): 它将无限期地阻塞,我的假设是控件将CheckInternetConnectionAsync()保留在“wait”关键字处,并阻塞在“.Result”上。等待恢复时,主线程已被阻塞并保持阻塞状态 我假设的原因是,我可以看到任务完成并返回,但wait之后的代码永远不会执行 但是,如果我这样做: bool result = Task.

我刚接触C#有着丰富的java背景,但仍在试图弄清楚Wait和async到底是如何工作的,以下是让我非常困惑的地方:

假设我有这样一个函数(下面的黑客代码仅用于实验):

它将无限期地阻塞,我的假设是控件将CheckInternetConnectionAsync()保留在“wait”关键字处,并阻塞在“.Result”上。等待恢复时,主线程已被阻塞并保持阻塞状态

我假设的原因是,我可以看到任务完成并返回,但wait之后的代码永远不会执行

但是,如果我这样做:

bool result = Task.Run(() => CheckInternetConnection()).Result;
然后执行wait语句之后的代码,并且主线程继续

我的预期是它也会阻塞,因为主线程会在中间任务上阻塞,。中间任务将在.Result上被阻止


那么…是什么造成了不同?在这种情况下,等待后的代码会执行什么?

在UI环境中,您有一个特殊的单线程
SynchronizationContext
,它在UI线程上运行所有内容。当您
等待
一项任务时,会捕获该上下文,当该任务完成时,方法会在该捕获的上下文上恢复(这可以使用
配置等待
进行配置):

SomeClass details = await ReturnARunningTask().ConfigureAwait(false);
在您的情况下,当您对未完成的任务使用
Task.Result
属性时,您正在同步阻止UI线程,因此当
CheckInternetConnectionAsync
尝试在
SynchronizationContext
上恢复时,在
ReturnARunningTask
完成后,它无法恢复。UI线程在等待e
CheckInternetConnectionAsync
任务,该任务依次等待UI线程,从而导致死锁(无限期阻塞)

使用
Task.Run(()=>CheckInternetConnection()时的差异.Result;
是指使用
任务.Run
卸载要在
线程池
线程上完成的工作。这些线程没有
同步上下文
,因此当UI线程在
上被阻塞时。Result
任务可以完成,因为它不需要UI线程来完成

不鼓励对异步操作()进行阻塞,因为它会阻塞线程,降低应用程序的响应速度和可伸缩性,并可能导致死锁。您应该始终使用
async wait


注意:与执行“通过
async
同步”不同,您应该让同步版本同步,如果您需要
async
版本将CPU密集型工作卸载到不同的线程,请使用
任务。运行

public static bool CheckInternetConnection()
{
    return checkInternet().IsSuccessful;
}

public async static Task<bool> CheckInternetConnectionAsync()
{
    if (NetworkInterface.GetIsNetworkAvailable())
    {
        return await Task.Run(() => CheckInternetConnection());
    }
    return false;
}
公共静态bool CheckInternetConnection()
{
返回checkInternet()。IsSuccessful;
}
公共异步静态任务CheckInternetConnectionAsync()
{
if(NetworkInterface.GetIsNetworkAvailable())
{
返回等待任务。运行(()=>CheckInternetConnection());
}
返回false;
}

这是什么类型的应用程序?控制台,wpf?这是一个运行在android上的xamarin应用程序,用C#…编写。问题是,如果我从UI线程调用await,它依次调用await等等,而不使用任何TPL东西,UI SyncContext是否总是在await上传递?@MatthewYang是的。除非使用Task.Run或Co,否则它会一次又一次地传递nfigureAwait(false)
SomeClass details = await ReturnARunningTask().ConfigureAwait(false);
public static bool CheckInternetConnection()
{
    return checkInternet().IsSuccessful;
}

public async static Task<bool> CheckInternetConnectionAsync()
{
    if (NetworkInterface.GetIsNetworkAvailable())
    {
        return await Task.Run(() => CheckInternetConnection());
    }
    return false;
}