使用ContinueWith时ConfigureAwait(false)

Wat*_* v2 6 c#

什么相当于使用:

await task.ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

当使用像这样的延续(不使用C#编译器的async/await转换)?

var taskOfString = ScheduleWorkOnThreadPoolAsync();

// I'd like this continuation to not have to
// "flow" the synchronization context but to simply
// execute wherever it can, i.e. I'd like to tell is
// ConfigureAwait(false) for its previous task.
// How do I do that?
taskOfString.ContinueWith(t => { });


public async Task<string> ScheduleWorkOnThreadPoolAsync()
{
  return Task.Run(() => return "Foo" );
}
Run Code Online (Sandbox Code Playgroud)

我假设什么都不做,即只是将其保留原样等同于调用ConfigureAwait(false),这也是我在调试代码时看到的情况.它可以在任何线程上跳跃.

只有当我们想要指定调度程序或同步上下文来运行延续时,我们才需要将额外的信息传递给接受a的重载TaskScheduler.否则,默认运行时不考虑执行上下文.

但是,如果我错了,我还是要求确认或更正.

Ste*_*ary 11

当使用像这样的continuation(不使用C#编译器的async/await转换)?

你应该几乎总是使用async/ await.它们具有更安全的默认行为.ContinueWith是一个危险的低级API.

我假设什么也不做,即只是将其保留原样等同于调用ConfigureAwait(false)...只有当我们想要指定调度程序或同步上下文来运行继续时我们需要传递额外的信息到接受TaskScheduler的重载.否则,默认运行时不考虑执行上下文.

不.这是不正确的,虽然简单的测试不会揭示问题.

正如我在我的博客文章描述的,为什么你不应该使用ContinueWith,默认TaskSchedulerContinueWith不是 TaskScheduler.Default.是的TaskScheduler.Current.由于这在每个场景中都很混乱,所以你应该总是传递TaskSchedulerContinueWithStartNew.

如果你想要await x.ConfigureAwait(false)行为,你实际上会这样做:

var continuation = x.ContinueWith(callback, CancellationToken.None,
    TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach,
    TaskScheduler.Default);
Run Code Online (Sandbox Code Playgroud)

TaskContinuationOptions.ExecuteSynchronously模仿的同步-IF-可能的行为await.该TaskContinuationOptions.DenyChildAttach如果继续任务防止问题连接到(用于异步任务时有子任务附加到他们令人惊讶的行为AttachedToParent).在TaskScheduler.Default模仿ConfigureAwait(false)总是在一个线程池上下文中执行的行为.

作为最后一点,您可能需要做一些事情continuation- 至少观察异常并以某种方式处理它们.

在这一点上,我应该清楚为什么我推荐await.在最坏的情况下,你只需要添加一个帮助方法来await代替ContinueWith- await更易于维护,IMO.


Mar*_*ell 4

我研究了Taskthen ConfiguredTaskAwaitablevia GetAwaiter.OnCompletedback through into Task.SetContinuationForAwait(使用continueOnCapturedContextas false)的参考源,它进入:

if (!AddTaskContinuation(tc, addBeforeOthers: false))
        tc.Run(this, bCanInlineContinuationTask: false);
Run Code Online (Sandbox Code Playgroud)

基本上,就是ContinueWith。所以:是的。

  • @WaterCoolerv2,但如果您不确定,请记住您也可以使用 `.ConfigureAwait(false).GetAwaiter().OnCompleted(callback)` - 当然不是那么直接 (3认同)