是否有人遇到使用ConfigureAwait(true)
的情况?由于true
是默认选项,因此我无法看到您何时使用它。
答案 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();
}
}