【问题标题】:When should I use ConfigureAwait(true)?什么时候应该使用 ConfigureAwait(true)?
【发布时间】:2014-01-19 15:23:48
【问题描述】:

有没有人遇到过使用ConfigureAwait(true) 的场景?因为true 是默认选项,所以我看不出你什么时候会使用它。

【问题讨论】:

    标签: c# asynchronous async-await configureawait


    【解决方案1】:

    true 尝试将延续编组回捕获的原始上下文;否则为假。

    实际上更像是说ConfigureAwait(true) 就像使用.ContinueWith( t => {...}, TaskScheduler.FromCurrentSynchronizationContext()),而ConfigureAwait(false) 就像使用.ContinueWith( t => {...})。如果传递 false,则允许继续在线程池线程上运行,而不是拉回当前同步上下文。

    【讨论】:

    • 很好的解释,虽然这只是解释ConfigureAwait(true) 做了什么,但没有解释何时有人会想要这样做。很高兴知道有人想要.ConfigureAwait(true) 的一些例子。是和根本不调用.ConfigureAwait() 一样,还是避免使用.ConfigureAwait() 会使代码随机使用或不使用当前上下文?例如,为什么有人需要在 ASP.NET MVC 应用程序中使用同步上下文?
    • 要了解更多关于什么是 SynchronizationContext 等等,请参阅What does SynchronizationContext do
    【解决方案2】:

    我可以看到的一种可能性是,如果您正在库中编写代码,并且您希望让您的调用者决定是否适合在原始上下文中继续1(尽管我通常会主张永远不要在库代码中继续使用原始上下文)

    您的调用者将传递一个bool 参数或设置一些配置值,因此直到运行时您才会知道正确的参数值是什么。


    这是 API 的一般答案类型,例如具有无参数变体和具有单个参数的变体的 API,其中无参数变体被记录为“与具有良好 -已知值 x" - 如果您直到运行时才知道要传递的正确值是什么,那么您应该使用正确的运行时值调用单个参数变体。


    1 例如你的来电者也提供了一个代表。您的调用者将知道(并且可以决定)该委托是否需要返回原始上下文。

    【讨论】:

    • 这个答案完美地描述了Pollylater took的方法。 if they are using a custom TaskScheduler 是调用者可能希望在原始上下文.ConfigureAwait(true) 上强制继续执行的一个真实示例。
    • 一个例外 - 线程静态访问,如 DbCommandInterceptor 模式
    • 此答案建议致电ConfigureAwait(boolVariable),这很好。但最初的问题是是否有理由这样做ConfigureAwait(true),听起来答案是否定的。
    【解决方案3】:

    因为 true 是默认选项,我看不出你什么时候会使用它。

    一个明显的用例是,当您希望确保每次等待某事时,都会对如何处理同步上下文做出明确而深思熟虑的选择。

    来自http://newmedialabs.co.za/blog/post/SynchronizationContexts 的示例政策:

    在 NML,我们更喜欢始终明确说明我们希望如何完成任务 继续发生。所以即使一个任务的默认值是 ConfigureAwait(true),我们仍然这样指定它,以便我们 始终了解“幕后”正在发生的事情。

    尽管为了提高可读性,他们直接使用扩展名而不是 ConfigureAwait(true)

    但是,当您查看大量代码时,有些代码带有 ConfigureAwait(true) 和一些带有 ConfigureAwait(false) 的,它不是 很容易发现它们的不同之处。所以我们使用 ConfigureAwait(false),或者一个有用的扩展方法, ContinueOnCapturedContext()。它做同样的事情,但只是 以更直观的方式将其与 ConfigureAwait(false) 区分开来。

    【讨论】:

    【解决方案4】:

    使用ConfigureAwait(true) 的情况是在锁中执行等待或使用任何其他上下文/线程特定资源时。这需要一个同步上下文,您必须创建它,除非您使用的是自动创建 UI 同步上下文的 Windows 窗体或 WPF。

    在以下代码中(假设从 UI 线程和同步上下文中调用),如果使用 ConfigureAwait(false),锁将尝试在不同的线程上释放,从而导致异常。这是一个简单的示例,如果从外部源更改了大型配置文件,则更新它,如果配置文件与以前相同,则尝试避免写入磁盘 IO。

    例子:

    /// <summary>
    /// Write a new config file
    /// </summary>
    /// <param name="xml">Xml of the new config file</param>
    /// <returns>Task</returns>
    public async Task UpdateConfig(string xml)
    {
        // Ensure valid xml before writing the file
        XmlDocument doc = new XmlDocument();
        using (XmlReader xmlReader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { CheckCharacters = false }))
        {
            doc.Load(xmlReader);
        }
        // ReaderWriterLock
        configLock.AcquireReaderLock(Timeout.Infinite);
        try
        {
            string text = await File.ReadAllTextAsync(ConfigFilePath).ConfigureAwait(true);
    
            // if the file changed, update it
            if (text != xml)
            {
                LockCookie cookie = configLock.UpgradeToWriterLock(Timeout.Infinite);
                try
                {
                    // compare again in case text was updated before write lock was acquired
                    if (text != xml)
                    {
                        await File.WriteAllTextAsync(ConfigFilePath, xml).ConfigureAwait(true);
                    }
                }
                finally
                {
                    configLock.DowngradeFromWriterLock(ref cookie);
                }
            }
        }
        finally
        {
            configLock.ReleaseReaderLock();
        }
    }
    

    【讨论】:

      【解决方案5】:

      如果您使用 Azure 的 Durable Functions,则在等待 Activity 函数时必须使用 ConfigureAwait(true)

      string capture = await context.CallActivityAsync<string>("GetCapture", captureId).ConfigureAwait(true);
      

      否则你可能会得到错误:

      “检测到多线程执行。如果编排器函数代码等待不是由 DurableOrchestrationContext 方法创建的任务,则可能会发生这种情况。更多详细信息可以在这篇文章https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-checkpointing-and-replay#orchestrator-code-constraints 中找到。”。

      更多信息可以在here找到。

      【讨论】:

      • 我认为他不是在问您何时希望该值为真,而是您何时真正想要指定它,因为它已经是默认值了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      • 2023-04-02
      • 2011-04-15
      • 2017-04-10
      • 2012-03-19
      相关资源
      最近更新 更多