我以为还在和调用者在同一个线程上等待,但似乎没有

时间:2014-02-17 20:27:02

标签: c# multithreading asynchronous async-await

我认为关于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来改变连续上下文的行为!

3 个答案:

答案 0 :(得分:33)

当您await时,默认情况下,await运算符会捕获当前的“上下文”,并使用它来恢复async方法。

此“上下文”为SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current。 (如果当前没有正在运行的任务,则TaskScheduler.CurrentTaskScheduler.Default(线程池任务调度程序)相同。

请注意,SynchronizationContextTaskScheduler并不一定意味着特定的主题。 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;
}