如何验证异步在特定情况下没有影响?

How to verify that async has no effect in a specific case?

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

bool empty = await Context.Stuff.AnyAsync();
if(empty)
  throw new Exception();

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

bool empty = Context.Stuff.Any();
if(empty)
  throw new Exception();

我如何验证我的声明(除了凭经验)?

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

Async 并不是关于“使其异步并且 运行s 更快”意义上的“更好的性能”——代码以相同的速率执行。异步是关于“更好地利用资源”——你需要更少的线程,而它们更多 busy/less 无所事事等待例如 IO 完成

如果它是一间办公室,则类似于在等待 phone 时煮咖啡;想象一下,您被煤气公司等候,而您的老板大声说他想要一杯咖啡。如果你是异步的,你会把它放在扬声器上,在你等待的时候起床煮咖啡,等待等待音乐停止的声音和煤气公司说“你好”的声音叫回来。如果你是同步的,你会坐在那里无视老板的要求,而其他人正在煮咖啡(这意味着老板必须雇用其他人)。让你坐在那里无所事事只是等待,并且不得不雇用其他人,这比你在工作 x 上达到一定程度然后去做其他事情要昂贵得多。如果你是异步的,你会在等待水壶烧开的时候去给打印机加水。如果你在等候同步,而办公室小辈正在同步等待水壶烧开,老板将不得不雇用另一个人来填充打印机..

当燃气公司最终让您停止等待时,是您还是其他人接听燃气公司的电话取决于您是否已经煮好咖啡并可以使用and/or您是否有 ConfigureAwait' d 表示必须是您接听电话 (true) 或办公室中是否有人可以接听电话 (false)

comments: I'm comparing it to using IEnumerable immediately followed by e.g. Count(), which will iterate through the whole shabang anyway. In that case, we may go T[] right away with no deteriorated performance. What's your thought on that?

这取决于您要对结果执行的其他操作。如果您需要反复询问结果的长度并随机访问它,那么请确定,使用 ToArrayAsync 将其转换为数组,然后将其作为本地缓存数据进行所有工作。除非结果是一个 2 TB 大的查询

如果您真的只需要计数一次,那么将所有内存用于分配数组并获取其长度是没有意义的;只需执行 CountAsync

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

确实非常快的操作,您可以同步它们以节省设置状态机的微不足道的成本,但要确定设置状态机的成本与线程可以做其他事情之间的临界点与让它等待时间相比;这台机器的成本非常低。面对选择,如果可用,我通常会选择异步,尤其是涉及到任何 IO 时

how to prove/refute whether it matters.

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

Hence, the following has no worse performance, I believe.

How can I verify my claim (other than empirically)?

除了经验之外,没有其他方法可以验证声明。其他任何东西都只是文字。您必须进行实验并亲眼看到差异,或者查看包含其他人进行的实验结果的屏幕截图。说到底还是得有人做实验才能验证。

我的猜测是,如果您进行实验,您会发现同步 Context.Stuff.Any() 应该具有与异步 await Context.Stuff.AnyAsync() 相同或更好的性能。如果更好,差异可能会很大。在 than 场合下,异步 APIs 已被证明比同步 APIs 慢。就我个人而言,我不知道有哪个 API 同时具有同步和异步版本,并且异步比同步更快。

您还没有问过哪个版本的可扩展性更高,因此您可能对等式的这方面不感兴趣。如果您有兴趣,进行比较这两个选项的可扩展性的实验会更加复杂。您不能只使用 Stopwatch 并测量单个操作的持续时间。您必须同时启动大量操作,并观察系统的整体行为。您可以获得 CPU 利用率、内存消耗、吞吐量等指标。我的期望是,在重负载下,异步版本应该提供比同步版本更好的指标,并且差异可能很大。

关于它的价值,您可以查看 here 我的一个有点愚蠢的实验,它证明异步 await Task.Delay() 比同步 Thread.Sleep() 更具可扩展性。后者每个操作需要一个线程。前者需要少量线程进行 100,000 次操作。