我试图找到答案,但无法解决。我想知道的是调用哪个线程Task.ContinueWith
委托。
等待我知道它尝试在捕获的SynchronizationContext
上运行它,但没有记录ContinueWith
。
我也尝试过一个示例程序,虽然它似乎是在Threadpool
线程上调用的,但我怀疑在某些情况下它可能会调用SynchronizationContext
。也许有人可以提供明确的答案。
答案 0 :(得分:3)
这取决于与continuation关联的调度程序。默认情况下,任务延续通过Current
调度程序进行调度,即与当前正在执行的任务相关联的TaskScheduler
。如果未在任务中调用ContinueWith
,Current
将返回Default
调度程序,这是.NET Framework提供的默认TaskScheduler
实例,并将安排您在线程池上的任务。
如果要影响此行为,可以调用带有ContinueWith
参数的TaskScheduler
重载之一。一种常见的模式是在UI线程上创建continuation时传递TaskScheduler.FromCurrentSynchronizationContext()
,因为这会导致在执行时将continuation调度回UI线程。
编辑:回复your comment:如果您从UI线程上运行的延续中生成子任务(旨在在线程池上运行),则可能会出现死锁。在这种情况下,子任务将从父任务继承任务调度程序,父任务将绑定到UI线程,从而导致子任务也在UI线程上运行。
Task.Factory.StartNew(() =>
{
// Do background work.
}).ContinueWith(_ =>
{
// Update UI, then spawn child task to do more background work...
Task.Factory.StartNew(() =>
{
// ...but child task runs on UI thread!
});
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
要解决此问题,您可以使用StartNew
重载接受子任务的TaskScheduler
参数,并将TaskScheduler.Default
传递给它:
// Update UI, then spawn child task to do more background work...
Task.Factory.StartNew(() =>
{
// ...and child task now runs on the thread pool.
},
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default);
答案 1 :(得分:2)
Task.ContinueWith
计划在TaskScheduler.Current
,除非其他一个可选重载中的参数另有说明。
如果TaskScheduler.Current
中没有自定义计划程序(很有可能),您的续约将在ThreadPool
上运行。
Task.ContinueWith
从不使用SynchronizationContext
,除非您使用TaskScheduler
创建TaskScheduler.FromCurrentSynchronizationContext
。
您始终可以使用其中一个可用重载明确说明需要TaskScheduler
:
task.ContinueWith(
_ => {},
null,
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default); // Scheduled to the ThreadPool