C# 什么';等待异步任务函数和在void函数中调用wait有什么区别?

C# 什么';等待异步任务函数和在void函数中调用wait有什么区别?,c#,.net,asynchronous,async-await,task,C#,.net,Asynchronous,Async Await,Task,要理解这个问题,请查看以下示例的wait调用和函数InitSyncContext()的定义 基于此,我想知道程序在每个场景中的行为,因为我不完全理解调用await InitSyncContext(store)和在内部调用await而不返回任务之间的区别 作为参考,我之前做过一项研究,我发现了一个类似的例子,但我认为在我的案例中是不同的 *下面的代码是来自真实世界代码的简化示例,仅用于演示目的 void Main() { Initializer(); } private async vo

要理解这个问题,请查看以下示例的
wait
调用和函数
InitSyncContext()
的定义

基于此,我想知道程序在每个场景中的行为,因为我不完全理解调用
await InitSyncContext(store)
和在内部调用
await
而不返回
任务之间的区别

作为参考,我之前做过一项研究,我发现了一个类似的例子,但我认为在我的案例中是不同的

*下面的代码是来自真实世界代码的简化示例,仅用于演示目的

void Main()
{
    Initializer();
}

private async void Initializer()
{
    var store = InitLocalStore();
    await InitSyncContext(store); // <-- Here, await call
    InitFileSync(store);
}

// Here returns Task (without having a return inside. No compile errors)
private async Task InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}

//------------- Second Method -------------

void Main()
{
    Initializer();
}

private void Initializer()
{
    var store = InitLocalStore();
    InitSyncContext(store); // <-- Here without await call
    InitFileSync(store);
}

// Here is void but with a async call inside
private async void InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}
void Main()
{
初始值设定项();
}
私有异步无效初始值设定项()
{
var store=InitLocalStore();

等待InitSyncContext(store);//在第一个示例中,编译器生成如下内容:

TheadPool.RunTask(()=>InitSyncContext(store)).ContinueWith(()=>InitFileSync(store))
第二,没什么有趣的。因为没有人等待任务结束。所有调用都将在主线程exept wait Client.SyncContext.InitializeAsync(store)中进行

等待异步任务函数和在void函数中调用wait有什么区别

这也许是一个非常大的问题,最好读一下斯蒂芬·克利里先生的精彩文章

一些总结要点:

避免异步无效-与异步无效方法相比,更喜欢异步任务方法

另见
  • Cleary,S,“异步/等待-异步编程的最佳实践”,2013年3月,微软,2016年7月14日检索
等待
async Task
函数与在
void
函数中调用
await
有什么区别

<全世界!一切……然后一些。让我们后退一步,从一些基础开始。

您应该选择“一路异步”,也就是说,如果您返回一个等待的(
任务
任务
),则应正确使用
异步
等待
关键字

这里有几件事需要澄清。你不应该有
async void
方法,相反,你应该有
async Task
——异常是事件处理程序(其中委托被预定义为非任务返回)等等。让我们来检查并区分方法一(我将忽略
入口点):

一个

private async void Initializer()
{
    var store = InitLocalStore();
    await InitSyncContext(store); // <-- Here, await call
    ...
}

// Here returns Task (without having a return inside. No compile errors)
private async Task InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}
事实上,情况已经变得越来越糟了!由于对异步命名法的误解,我们假设,既然有一种方法似乎可以“正常”工作没有考虑到其他方法可能遵循的最佳实践。您使
InitSyncContext
方法
async void
。方法不应该是
async void
的原因是它们是激发和遗忘的。内部异步状态机没有可锁定的
任务,因此状态丢失。当您删除调用方的
wait
时,您说的是启动此异步操作,但您不关心它的结果

以下是实现所需功能的正确方法:

正确

private async Task InitializerAsync()
{
    var store = InitLocalStore();
    await InitSyncContextAsync(store);
    ...
}

// Simply return the task that represents the async operation and let the caller await it
private Task InitSyncContextAsync(MobileServiceSQLiteStore store)
{
    return Client.SyncContext.InitializeAsync(store);
}
关于代码段中的
Main
方法的说明,如果这是控制台应用程序的一部分,则异步堆栈的顶级入口点将调用
.Result
.Wait()

进一步阅读


不能在非异步方法中使用await关键字。它在C#语言中是无效的语法。这不正确compile@SteveCooper感谢您指出。我更正了示例。此代码取自真实世界的代码(但没有主定义),因此我可以对其进行测试。这种方式编译。“”@米基德-坚持这个作为答案。我会投票…@hbob事实上是的,这就是问题所在,但我的问题是在类似的环境中(不一定使用Xamarin,但使用C#)将如何表现
wait
).要使用类内构造函数中的
wait
方法,我实现了这里描述的工厂模式,并且我没有尝试在控制台应用程序中使用Xamarin。我知道。这很简单。建议添加在引用站点上找到的答案摘要“异步堆栈的顶级入口点将调用.Result或.Wait()”您的意思是需要在
Main()
中执行一些特殊操作吗?那会是什么?如果我们一直使用“异步”“,您如何处理
Main
不是异步的事实?@hbob,是的。既然
Main
正在调用
async
方法链,我们需要确保调用
。Wait()
。当然,假设这是一个控制台应用程序。哦,您的意思是在控制台的
Main
函数内部(如OP的示例中所示)我们会做
初始化同步().Wait()
,这会使它“一路异步”?(虽然会被阻塞,但我想这是有道理的,所以应用程序不会退出。)@hbob没错,在控制台应用程序中,在应用程序的入口点没有对
异步
的本机支持。想想看,如果您在命令行上试图调用
.exe
它不知道什么是
任务
。有关详细信息,请参阅和。
private async Task InitializerAsync()
{
    var store = InitLocalStore();
    await InitSyncContextAsync(store);
    ...
}

// Simply return the task that represents the async operation and let the caller await it
private Task InitSyncContextAsync(MobileServiceSQLiteStore store)
{
    return Client.SyncContext.InitializeAsync(store);
}