了解TaskScheduler的行为.现在的

本文关键字:TaskScheduler 了解 | 更新日期: 2023-09-27 17:58:14

这里有一个简单的WinForms应用程序:

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private async void button1_Click(object sender, EventArgs e)
        {
            var ts = TaskScheduler.FromCurrentSynchronizationContext();
            await Task.Factory.StartNew(async () =>
            {
                Debug.WriteLine(new
                {
                    where = "1) before await",
                    currentTs = TaskScheduler.Current,
                    thread = Thread.CurrentThread.ManagedThreadId,
                    context = SynchronizationContext.Current
                });
                await Task.Yield(); // or await Task.Delay(1)
                Debug.WriteLine(new
                {
                    where = "2) after await",
                    currentTs = TaskScheduler.Current,
                    thread = Thread.CurrentThread.ManagedThreadId,
                    context = SynchronizationContext.Current
                });
            }, CancellationToken.None, TaskCreationOptions.None, scheduler: ts).Unwrap();
        }
    }
}

调试输出(单击按钮时):

{其中=1)等待之前,currentTs=System.Threading.Tasks.SynchronizationContextTaskScheduler,thread=9,context=System.Windows.Forms.WindowsFormsSynchronizationContext}{其中=2)等待后,currentTs=System.Threading.Tasks.ThreadPoolTaskScheduler,thread=9,context=System.Windows.Forms.WindowsFormsSynchronizationContext}

问题:为什么TaskScheduler.Currentawait之后从SynchronizationContextTaskScheduler变为ThreadPoolTaskScheduler

这本质上展示了TaskCreationOptions.HideSchedulerawait连续性的行为,在我看来,这是出乎意料和不可取的。

这个问题是由我的另一个问题引发的:

AspNetSynchronizationContext和等待ASP中的继续。NET。

了解TaskScheduler的行为.现在的

如果没有实际执行的任务,则TaskScheduler.CurrentTaskScheduler.Default相同。换句话说,ThreadPoolTaskScheduler实际上同时充当线程池任务调度器,意思是"没有当前任务调度器"。

async委托的第一部分使用SynchronizationContextTaskScheduler显式调度,并在具有任务调度程序和同步上下文的UI线程上运行。任务调度程序将委托转发到同步上下文。

await捕获其上下文时,它捕获同步上下文(而不是任务调度程序),并使用该syncctx来恢复。因此,方法continuation被发布到syncctx,syncctx在UI线程上执行它。

当延续在UI线程上运行时,它的行为与事件处理程序非常相似;委托是直接执行的,而不是包装在任务中。如果你在button1_Click的开头检查TaskScheduler.Current,你会发现它也是ThreadPoolTaskScheduler

顺便说一句,我建议您将这种行为(直接执行委托,而不是封装在任务中)视为实现细节。