我从Noeratio中读到了这个问题,它显示了一种行为,在awaitable完成操作后,TaskScheduler.Current
与不一样。
答案是:
如果没有正在执行的实际任务,则
TaskScheduler.Current
与TaskScheduler.Default
相同
这是真的。我已经在这里看到了:
TaskScheduler.Default
- 返回
ThreadPoolTaskScheduler
的实例TaskScheduler.Current
- 如果从执行任务中调用,将返回
TaskScheduler
的- 如果从任何其他地方调用,将返回
TaskScheduler.Default
但后来我想,如果是这样的话,让我们做创建一个实际的Task
(而不仅仅是Task.Yield()
(并测试它:
async void button1_Click_1(object sender, EventArgs e)
{
var ts = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(async () =>
{
MessageBox.Show((TaskScheduler.Current == ts).ToString()); //True
await new WebClient().DownloadStringTaskAsync("http://www.google.com");
MessageBox.Show((TaskScheduler.Current == ts).ToString());//False
}, CancellationToken.None, TaskCreationOptions.None,ts).Unwrap();
}
第一个Messagebox为"True",第二个为"False">
问题:
正如你所看到的,我确实创建了一个实际的任务。
我能理解为什么第一个MessageBox会产生True
。这是因为:
如果从正在执行的任务中调用,将返回TaskScheduler当前执行任务的
该任务确实具有ts
,即发送的TaskScheduler.FromCurrentSynchronizationContext()
但是为什么上下文没有保存在第二个MessageBox?对我来说,斯蒂芬的回答并不清楚。
附加信息:
如果我写(而不是第二个消息框(:
MessageBox.Show((TaskScheduler.Current == TaskScheduler.Default).ToString());
它确实产生CCD_ 14。但为什么呢?
混淆的原因如下:
- UI没有"特殊"的
TaskScheduler
。在UI线程上运行的代码的默认情况是TaskScheduler.Current
存储ThreadPoolTaskScheduler
,SynchronizationContext.Current
存储WindowsFormsSynchronizationContext
(或其他UI应用程序中的相关代码( TaskScheduler.Current
中的ThreadPoolTaskScheduler
并不一定意味着它是用于运行当前代码段的TaskScheduler
。它也意味着TaskSchdeuler.Current == TaskScheduler.Default
,因此"没有使用TaskScheduler
">TaskScheduler.FromCurrentSynchronizationContext()
不返回"实际"TaskScheduler
。它返回一个"代理",将任务直接发布到捕获的SynchronizationContext
因此,如果您在开始任务之前(或在任何其他地方(运行测试,您将获得与等待后相同的结果:
MessageBox.Show(TaskScheduler.Current == TaskScheduler.FromCurrentSynchronizationContext()); // False
因为CCD_ 28是CCD_ 29,而CCD_。
这是您的示例的流程:
- 您可以从UI的
SynchronizationContext
(即WindowsFormsSynchronizationContext
(创建一个新的SynchronizationContextTaskScheduler
- 在该
TaskScheduler
上安排使用Task.Factory.StartNew
创建的任务。由于它只是一个"代理",它将委托发布到WindowsFormsSynchronizationContext
,CCD_37在UI线程上调用它 - 该方法的同步部分(第一次等待之前的部分(在UI线程上执行,同时与
SynchronizationContextTaskScheduler
相关联 - 该方法到达等待并在捕获该
WindowsFormsSynchronizationContext
时被"挂起"> - 当在等待之后继续时,它被发布到
WindowsFormsSynchronizationContext
而不是SynchronizationContextTaskScheduler
,因为SynchronizationContext
具有优先级(这可以在Task.SetContinuationForAwait
中看到(。然后它在UI线程上定期运行,没有任何"特殊"的TaskScheduler
,因此TaskScheduler.Current == TaskScheduler.Default
因此,创建的任务在使用SynchronizationContext
的代理TaskScheduler
上运行,但等待之后的继续被发布到该SynchronizationContext
而不是TaskScheduler
。