如何验证异步在特定情况下没有效果?

Kon*_*ten 2 c# async-await asp.net-core-6.0 .net-6.0

在使用asyncand时await,有时我会遇到一个让我讨厌使用它的地方,因为我觉得它毫无意义。我还没有成功证明情况也是如此(而且,诚然,保留它不会损害性能)。我如何在以下示例中验证(或拒绝)我的主张。

bool empty = await Context.Stuff.AnyAsync();
if(empty)
  throw new Exception();
Run Code Online (Sandbox Code Playgroud)

我的主张是 - 由于我们立即使用检查结果来验证是否应该离开该方法,因此该调用需要同步启动。因此,我相信以下内容没有更差的表现。

bool empty = Context.Stuff.Any();
if(empty)
  throw new Exception();
Run Code Online (Sandbox Code Playgroud)

我如何验证我的主张(除了经验之外)?

Cai*_*ard 6

我同意所有的评论;这与您对结果执行什么操作以及何时执行无关,而与在异步操作执行时允许执行代码的线程执行其他操作无关。如果 Stuff 是数据库中基于需要 5 分钟运行的查询的复杂视图,则 Any 会阻塞您的线程 5 分钟。AnyAsync 可以让该线程同时向您的网络服务器发送数以万计的请求。如果您阻塞了一个线程,网络服务器将不得不启动另一个线程来为其他人服务,并且线程的成本很高。

异步并不是“让它异步并且运行得更快”意义上的“更好的性能”——代码以相同的速率执行。异步是关于“更好地利用资源”——你需要更少的线程,它们会更忙/更少无所事事地等待 IO 完成

如果是在办公室,这就类似于在打电话时煮咖啡;想象一下,你被天然气公司搁置了,你的老板大声说他想要一杯咖啡。如果你是异步的,你会把它放在扬声器上,在等待时起身煮咖啡,等待等待音乐停止的声音和燃气公司说“你好”的声音回电。如果你是同步的,你就会坐在那里,忽略老板的要求,而其他人则在煮咖啡(这意味着老板必须雇用其他人)。让你无所事事地等待,不得不雇用其他人,比你在工作 x 上达到一定程度然后去做其他事情的成本更高。如果你是异步的,你会在等待水壶沸腾的同时去给打印机加水。如果你的同步处于搁置状态,而办公室初级员工正在同步等待水壶烧开,那么老板将不得不雇用另一个人来填充打印机。

当天然气公司最终让您不再等待时,无论是您还是其他人接听打给您的电话,取决于您是否已经煮好咖啡并且有空和/或您是否已配置等待以表明必须这样做您接听电话 (true) 或办公室中的任何人是否可以继续接听电话 (false)

评论:我将其与使用 IEnumerable 进行比较,然后立即使用 Count(),无论如何它都会迭代整个 shabang。在这种情况下,我们可以立即进入 T[],而不会降低性能。你对此有何看法?

这取决于您将如何处理结果。如果您需要重复询问结果的长度并随机访问它,那么当然,请使用ToArrayAsync将其转换为数组,然后将其作为本地缓存数据进行所有工作。除非查询结果有 2 TB 大

如果您实际上只需要计数一次,那么花费所有内存来分配数组并获取其长度是没有意义的;只是做CountAsync

这些似乎都不与“是否异步?”的问题完全相关。- 如果您的 IEnumerable 通过慢速网络传输,并且是一些巨大的慢速查询,它仍然会返回“让线程关闭并忙于做其他事情,这样您就不必启动更多线程”。请注意,这里的“慢”甚至可能意味着几十毫秒。我们不必谈论分钟操作就能看到异步的好处

当然,操作速度非常快,您可以将它们同步以节省设置状态机的微小成本,但要确定设置状态机的成本之间的临界点,以便线程可以执行其他操作与使其等待量时间;这台机器的成本非常低。面对选择,如果可用的话,我通常会选择异步,特别是涉及任何 IO 时

如何证明/反驳它是否重要。

你必须为每种情况进行赛马;操作完成同步的速度有多快,执行异步状态管理需要多长时间。对于整个代码库来说,这可能是相当令人厌烦的,这就是为什么我倾向于继续“如果异步可用并且不仅仅是为了异步而可用,那么可能有人认为使用异步是明智的,所以我们应该使用它”的基础。如果您使用它在库中的存在作为您应该在代码中利用它的指示器(然后向代码的用户表明他们应该......),那么异步在代码库中一路向上传播可能是一件好事