Hier ist eine einfache WinForms App:das Verhalten von TaskScheduler.Current
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();
}
}
}
Die Debug ouput (wenn die Schaltfläche geklickt wird):
{ where = 1) before await, currentTs = System.Threading.Tasks.SynchronizationContextTaskScheduler, thread = 9, context = System.Windows.Forms.WindowsFormsSynchronizationContext } { where = 2) after await, currentTs = System.Threading.Tasks.ThreadPoolTaskScheduler, thread = 9, context = System.Windows.Forms.WindowsFormsSynchronizationContext }
Die Frage: Warum istTaskScheduler.Current
Wechsel von SynchronizationContextTaskScheduler
bis ThreadPoolTaskScheduler
nach await
hier?
Dies zeigt im Wesentlichen das Verhalten TaskCreationOptions.HideScheduler
für await
Fortsetzung, die meiner Meinung nach unerwartet und unerwünscht ist.
Diese Frage wurde durch eine andere Frage von mir ausgelöst:
AspNetSynchronizationContext and await continuations in ASP.NET.
Dies ist, wie ich dachte, es funktioniert, aber wollte nicht ohne ein bisschen mehr Informationen kommentieren. +1. –
Ich sehe, anscheinend funktioniert so 'TaskAwaiter'. IMO, das Design, das sie für "fließendes" 'TaskScheduler.Current' entworfen haben, ist eher verwirrend: Normalerweise ist es nicht das, was Sie logisch erwarten würden. – Noseratio
Einverstanden; 'TaskScheduler.Current' wurde mit dynamischer Parallelität entworfen, so dass untergeordnete Tasks den Scheduler von ihren übergeordneten Tasks erben. Dieses Standardverhalten ist für asynchrone Tasks verwirrend, weshalb ich darauf bestehe, den Scheduler in jedem 'StartNew' und' ContinueWith' explizit anzugeben. –