这是一个简单的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();
}
}
}
调试输出(单击按钮时):
{ where = 1) 在 await 之前,currentTs = System.Threading.Tasks.SynchronizationContextTaskScheduler,thread = 9,context = System.Windows.Forms.WindowsFormsSynchronizationContext } { where = 2) 在 await 之后,currentTs = System.Threading.Tasks.ThreadPoolTaskScheduler,thread = 9,context = System.Windows.Forms.WindowsFormsSynchronizationContext }
问题:为什么TaskScheduler.Current
在这里await
之后从SynchronizationContextTaskScheduler
更改为ThreadPoolTaskScheduler
?
这基本上展示了TaskCreationOptions.HideScheduler
用于await
继续的行为,我认为这是意外和不希望的。
这个问题是由我的另一个问题引发的:
AspNetSynchronizationContext and await continuations in ASP.NET.
TaskAwaiter
的工作原理。在我看来,他们为“流动”TaskScheduler.Current
设计的方式相当令人困惑:通常它不是你逻辑上期望的那样。 - noseratio - open to workTaskScheduler.Current
被设计用于动态并行性,使得子任务可以从父任务继承调度器。这种默认行为对于异步任务来说是令人困惑的,因此我坚持在每个StartNew
和ContinueWith
中明确指定调度器。 - Stephen Cleary