了解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.Current
在await
之后从SynchronizationContextTaskScheduler
变为ThreadPoolTaskScheduler
?
这本质上展示了TaskCreationOptions.HideScheduler
对await
连续性的行为,在我看来,这是出乎意料和不可取的。
这个问题是由我的另一个问题引发的:
AspNetSynchronizationContext和等待ASP中的继续。NET。
如果没有实际执行的任务,则TaskScheduler.Current
与TaskScheduler.Default
相同。换句话说,ThreadPoolTaskScheduler
实际上同时充当线程池任务调度器和,意思是"没有当前任务调度器"。
async
委托的第一部分使用SynchronizationContextTaskScheduler
显式调度,并在具有任务调度程序和同步上下文的UI线程上运行。任务调度程序将委托转发到同步上下文。
当await
捕获其上下文时,它捕获同步上下文(而不是任务调度程序),并使用该syncctx来恢复。因此,方法continuation被发布到syncctx,syncctx在UI线程上执行它。
当延续在UI线程上运行时,它的行为与事件处理程序非常相似;委托是直接执行的,而不是包装在任务中。如果你在button1_Click
的开头检查TaskScheduler.Current
,你会发现它也是ThreadPoolTaskScheduler
。
顺便说一句,我建议您将这种行为(直接执行委托,而不是封装在任务中)视为实现细节。