c# - Task.ContinueWith 回调线程

标签 c# .net multithreading task-parallel-library task

我试图为此找到答案,但找不到。我想知道在哪个线程上调用 Task.ContinueWith 委托(delegate)。 对于 await,我知道它会尝试在捕获的 SynchronizationContext 上运行它,但没有为 ContinueWith 记录任何内容。

我还尝试了一个示例程序,虽然它似乎是在 Threadpool 线程上调用的,但我怀疑在某些情况下它可能会在 SynchronizationContext 上调用。也许有人可以提供明确的答案。

最佳答案

这取决于与延续关联的调度程序。默认情况下,任务延续是通过 Current 安排的。调度程序,是与当前正在执行的任务关联的 TaskScheduler。当 ContinueWith 未从任务中调用时,Current 将返回 Default调度程序,这是 .NET Framework 提供的默认 TaskScheduler 实例,它将在线程池上安排您的任务。

如果您想影响此行为,您可以调用带有 TaskScheduler 参数的 ContinueWith 重载之一。一种常见的模式是在 UI 线程上创建延续时传递 TaskScheduler.FromCurrentSynchronizationContext(),因为这会导致延续在执行时分派(dispatch)回 UI 线程。

编辑:回复your comment :如果您从在 UI 线程上运行的延续生成子任务(旨在在线程池上运行),则可能会出现死锁。在这种情况下,子任务将从父任务继承任务调度程序,父任务将绑定(bind)到 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());

要解决此问题,您可以使用接受子任务的 TaskScheduler 参数的 StartNew 重载,并将 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);

关于c# - Task.ContinueWith 回调线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33051211/

相关文章:

java - 平衡多个队列

c# - 当我尝试执行Web应用程序时出现此错误消息

C# 锁线程问题

c# - System.Threading.ThreadPool.QueueUserWorkItem C# 的动态回调方法

c# - Linq 结果到 IEnumerable 无效转换

c++ - 奇怪的 C++ 线程函数调用

multithreading - 为什么我在使用 Async.Parallel 时只有一个线程 id?

c# - 没有打开IE窗口时,如何在C#中打开多个IE选项卡?

c# - 在 Winforms 和 .net 中难以在设计时保留引用内部属性的集合

c# - 如何确保文件是有效的音频文件并且不受 DRM 保护?