Task.ContinueWith回调线程 [英] Task.ContinueWith callback thread
问题描述
我试图为此找到答案,但是找不到.我想知道的是在哪个线程上调用了Task.ContinueWith
委托.
等待,我知道它会尝试在捕获的SynchronizationContext
上运行它,但是没有任何文档记录ContinueWith
.
I tried to find an answer for this but couldn't. What I was wondering is that on which thread Task.ContinueWith
delegate is called.
For await I know that it tries to run it on the captured SynchronizationContext
but there is nothing documented for ContinueWith
.
我也尝试了一个示例程序,尽管它似乎是在Threadpool
线程上调用的,但我怀疑在某些情况下它可能会在SynchronizationContext
上调用.也许有人可以提供明确的答案.
I also tried with a sample program and though it seems it is called on Threadpool
thread, I suspect that in some scenario it might call on SynchronizationContext
. Maybe someone can provide a definitive answer.
推荐答案
这取决于与延续相关联的调度程序.默认情况下,任务继续是通过 Current
调度程序,是与当前正在执行的任务关联的TaskScheduler
.如果未从任务内调用ContinueWith
,则Current
将返回
This depends on the scheduler that is associated with the continuation. By default, task continuations are scheduled through the Current
scheduler, being the TaskScheduler
associated with the currently executing task. When ContinueWith
is not called from within a task, Current
will return the Default
scheduler, which is the default TaskScheduler
instance provided by the .NET Framework, and which will schedule your tasks on the thread pool.
如果要影响此行为,可以调用采用TaskScheduler
参数的ContinueWith
重载之一.一种常见的模式是在UI线程上创建延续时传递TaskScheduler.FromCurrentSynchronizationContext()
,因为这将导致在执行时将延续分派回UI线程.
If you want to influence this behaviour, you can call one of the ContinueWith
overloads that takes a TaskScheduler
parameter. A common pattern is to pass TaskScheduler.FromCurrentSynchronizationContext()
when creating continuations on the UI thread, as this would cause the continuation to be dispatched back onto the UI thread when executed.
编辑:回复您的评论:如果您从UI线程上运行的延续生成子任务(打算在线程池上运行),则可能会出现死锁.在这种情况下,子任务将从父任务继承任务调度程序,该任务调度程序将绑定到UI线程,从而导致子任务也可以在UI线程上运行.
Edit: In reply to your comment: The deadlock may arise if you spawn a child task (intended to run on the thread pool) from a continuation running on the UI thread. In such cases, the child task will inherit the task scheduler from the parent task, which would be bound to the UI thread, causing the child task to run on the UI thread too.
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
传递给它:
To resolve this, you can use the StartNew
overload that accepts a TaskScheduler
parameter for the child task, and pass TaskScheduler.Default
to it:
// 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);
这篇关于Task.ContinueWith回调线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!