Vik*_*nov 4 c# async-await .net-core
问题不在于 ConfigureAwait 做什么。但更确切地说,为什么我到处都能看到类似的东西
一般来说,是的。除非该方法需要其上下文,否则应为每个等待使用 ConfigureAwait(false)。
即他们建议我应该写
await Method1().ConfigureAwait(false);
await Method2().ConfigureAwait(false);
// Do something else
// ...
await Method3().ConfigureAwait(false);
await Method4().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)
但在这种情况下,只在一开始就重置上下文不会更清楚,就像
await Task.Yield().ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)
它保证下面的代码将在没有同步上下文的情况下执行,不是吗?
即我读到如果该方法立即返回,则写一次 ConfigureAwait 可能不起作用。对我来说,显而易见的解决方案看起来像调用 ConfigureAwait(false) 肯定不会立即返回的东西,Task.Yield 是什么,对吧?
另外我知道 Task.Yield 不再包含 ConfigureAwait(不知道为什么,因为我知道它以前曾经有它),但是查看 Task.Yield 代码很容易编写自己的方法除了用空的同步上下文调用延续之外,什么都不做。
对我来说,阅读似乎要容易得多,尤其是当你写一次的时候写
await TaskUtility.ResetSyncContext();
Run Code Online (Sandbox Code Playgroud)
而不是在每一行上写 ConfigureAwait。
这会起作用(Task.Yield().ConfigureAwait(false) 或类似的自定义方法)还是我错过了什么?
一般来说,是的。除非该方法需要其上下文,否则应为每个等待使用 ConfigureAwait(false)。
我经常在 Stack Overflow 上看到这样的建议,甚至 Stephen Cleary(微软 MVP)在他的Async 和 Await文章中也说过:
一个好的经验法则是使用 ConfigureAwait(false) 除非您知道您确实需要上下文。
斯蒂芬肯定知道他的东西,我同意这个建议在技术上是准确的,但我一直认为这是一个糟糕的建议,原因有两个:
首先,这对初学者来说是个坏建议,因为同步上下文是一个复杂的主题。如果您开始学习async
/await
被告知“除非方法需要其上下文,否则ConfigureAwait(false)
应该用于每个await
”,但您甚至不知道“上下文”是什么以及“需要它”意味着什么,那么您就不会知道什么时候不应该使用它,所以你最终总是使用它。这意味着你可能会遇到很难弄清楚的错误,除非你碰巧知道,是的,你确实需要那个“上下文”的东西,而这个神奇的“ConfigureAwait”东西让你失去了它。您可能会花费数小时试图弄清楚这一点。
对于任何类型的应用程序,我认为建议确实应该相反:根本不要使用ConfigureAwait
,除非您知道它的作用并且您已经确定在该行之后绝对不需要上下文。
但是,确定您不需要上下文可以是简单的,也可以是非常复杂的,具体取决于之后调用的方法。但即便如此-这是第二个原因我那个建议不同意-只是因为你并不需要这一行后的背景下,现在,这并不意味着一些代码不会在以后添加,将使用的上下文。您必须希望做出这种改变的人知道做什么ConfigureAwait(false)
,看到它并删除它。ConfigureAwait(false)
随处使用会产生维护风险。
这是另一位 Stephen Toub(Microsoft 员工)在ConfigureAwait 常见问题解答中的“何时应该使用 ConfigureAwait(false)?”副标题下的建议:
在编写应用程序时,您通常需要默认行为(这就是为什么它是默认行为)。...这导致了以下一般指导:如果您正在编写应用程序级代码,请不要使用
ConfigureAwait(false)
在我自己的应用程序代码中,我不会费心去弄清楚哪些地方可以使用,哪些地方不能使用。我只是忽略它的ConfigureAwait
存在。当然,通过尽可能使用它可以提高性能,但我真的怀疑它对任何人来说都会有明显的差异,即使它可以通过计时器进行测量。我不相信投资回报是积极的。
唯一的例外是在编写库时,正如 Stephen Toub 在他的文章中指出的那样:
如果您正在编写通用库代码,请使用
ConfigureAwait(false)
这有两个原因:
要解决您问题中的另一点:ConfigureAwait(false)
在第一个await
而不是其余部分上使用并不总是足够的。使用它的每一个 await
库中的代码。Stephen Toub 的文章标题为“是否可以仅在我的方法中的第一个 await 上使用 ConfigureAwait(false) 而不是在其余部分上使用?” 部分说:
如果
await task.ConfigureAwait(false)
涉及到在等待时已经完成的任务(这实际上非常常见),那么ConfigureAwait(false)
将毫无意义,因为线程在此之后继续执行方法中的代码,并且仍然处于与之前相同的上下文中。
归档时间: |
|
查看次数: |
875 次 |
最近记录: |