我什么时候应该使用ConfigureAwait(true)

时间:2014-01-02 07:48:33

标签: c# asynchronous

是否有人遇到使用ConfigureAwait(true)的情况?由于true是默认选项,因此我无法看到您何时使用它。

5 个答案:

答案 0 :(得分:12)

如果尝试将延续编组回到捕获的原始上下文,则为true;否则,错误。

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

答案 1 :(得分:6)

我可以看到的一种可能性是,如果您在库中编写代码,并且您希望允许您的调用者决定是否继续使用原始上下文 1 (尽管我通常会这样做)争论永远不要继续从图书馆代码中的原始背景继续下去)

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


这是API的一般类型的答案,例如具有no-args变体和具有单个参数的变体,其中no-args变体被记录为“与具有良好的单个参数变体相同”已知值 x “ - 如果您在运行时之前不知道要传递的正确值是什么,那么您应该使用正确的运行时值调用单个参数变量。


1 例如你的来电者也在提供代表。您的呼叫者将知道(并且可以决定)该代表是否需要回到原始上下文。

答案 2 :(得分:5)

  

由于true是默认选项,我无法看到你何时会使用它。

一个明显的用例是,当您想要确保每次等待某些事情时,都会明确而谨慎地选择如何处理同步上下文。

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

  

在NML,我们更愿意明确说明我们想要的任务   继续发生。即使任务的默认值是   ConfigureAwait(true),我们仍然这样指定它,以便我们这样做   始终认识到“引擎盖下”正在发生的事情。

虽然为了提高可读性,他们直接使用扩展名代替#Some simple code as context: data=cbind(rnorm(5)+1,rnorm(5)+1,rnorm(5)+1) par=c(0.5,0.3,0.2) fn=function(par,data) {return(as.numeric(rep(1,times=5)%*%(data%*%par)))} #setting the conditions that the sum of the parameters must be 1: u1<-rbind(c(1,1,1),c(-1,-1,-1)) c1<-c(0.999, -1.001) constr.optim1<-constrOptim(c(0.3,0.3,0.4), f=fn, data=data,grad=NULL, ui=u1, ci=c1) sum(constr.optim1$par) #=0.99997 which is close enough to 1 as specified #But how would I set/restrict: length(which(constr.optim1$par!=0)) #to equal 2 and not 3?

  

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

答案 3 :(得分:1)

如果您正在使用Azure的持久功能,那么在等待“活动”功能时必须使用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

答案 4 :(得分:0)

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

在以下代码中(假定从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();
    }
}