Task.ContinueWith callback thread

前端 未结 2 1512
一向
一向 2021-01-06 12:09

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 tr

相关标签:
2条回答
  • 2021-01-06 12:26

    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.

    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.

    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());
    

    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);
    
    0 讨论(0)
  • 2021-01-06 12:46

    Task.ContinueWith is scheduled on the TaskScheduler.Current unless specified otherwise by the parameters in one of the optional overloads.

    If you don't have a custom scheduler in TaskScheduler.Current (which is very likely) your continuation will run on the ThreadPool.

    Task.ContinueWith never uses the SynchronizationContext unless you create a TaskScheduler out of it with TaskScheduler.FromCurrentSynchronizationContext.

    You can always state explicitly which TaskScheduler is needed using one of the available overloads:

    task.ContinueWith(
        _ => {}, 
        null, 
        CancellationToken.None, 
        TaskContinuationOptions.None, 
        TaskScheduler.Default); // Scheduled to the ThreadPool
    
    0 讨论(0)
提交回复
热议问题