我认为关于async / await的一点是,当任务完成时,继续在调用await时在相同的上下文上运行,在我的例子中,这将是UI线程。
例如:
Debug.WriteLine("2: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
await fs.ReadAsync(data, 0, (int)fs.Length);
Debug.WriteLine("3: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
我不希望这样:
2: Thread ID: 10
3: Thread ID: 11
是什么给出的?为什么延续的线程ID与UI线程不同?
根据this article [^]我需要显式调用ConfigureAwait来改变连续上下文的行为!
答案 0 :(得分:33)
当您await
时,默认情况下,await
运算符会捕获当前的“上下文”,并使用它来恢复async
方法。
此“上下文”为SynchronizationContext.Current
,除非它是null
,在这种情况下它是TaskScheduler.Current
。 (如果当前没有正在运行的任务,则TaskScheduler.Current
与TaskScheduler.Default
(线程池任务调度程序)相同。
请注意,SynchronizationContext
或TaskScheduler
并不一定意味着特定的主题。 UI SynchronizationContext
将为UI线程安排工作;但是ASP.NET SynchronizationContext
不会将工作安排到特定的线程。
我怀疑您的问题的原因是您过早地调用了async
代码。当应用程序启动时,它只有一个普通的常规线程。当该线程执行Application.Run
之类的操作时,该线程仅成为UI线程。
答案 1 :(得分:5)
await
表达式将使用SynchronizationContext.Current
的值将控制流返回到发生它的线程。如果是null
,则默认为TaskScheduler.Current
。当Task
值完成时,实现仅依赖于此值来更改线程上下文。听起来好像在这种情况下await
正在捕获未绑定到UI线程的上下文
答案 2 :(得分:-1)
默认情况下,Windows 窗体在创建第一个控件时设置同步上下文。
所以你可以这样做:
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var f = new Form1();
//var s=SynchronizationContext.Current;
//var s2=TaskScheduler.Current;
GetAsync();
Application.Run(f);
}
static async Task<bool> GetAsync()
{
MessageBox.Show($"thread id {Thread.CurrentThread.ManagedThreadId}");
bool flag = await Task.Factory.StartNew<bool>(() =>
{
Thread.Sleep(1000);
return true;
});
MessageBox.Show($"thread id {Thread.CurrentThread.ManagedThreadId}");
return flag;
}