异步.NET控制台程序中的线程控制流

时间:2019-04-25 09:11:16

标签: c# .net async-await threadpool

我在C#中搞乱了async / await,只是想深入研究一些线程控制流,偶然发现了一个不寻常的行为,对此我非常感谢您进行澄清。 即使任务本身是在后台执行的,等待后的执行仍会在调用线程上继续进行是有意义的。实际上,这就是WPF发生的情况。
以下代码:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    Console.WriteLine($"Start. Thread: {Thread.CurrentThread.ManagedThreadId}");
    await Task.Run(async () => await Task.Delay(1000));
    Console.WriteLine($"End. Thread: {Thread.CurrentThread.ManagedThreadId}");
}

结果在:
开始。线程:1
结束。线程:1

我意识到那是使程序流程可预测的方法。

但是令我惊讶的是.NET Console应用程序的异步Main方法功能显示出一些不同的行为。
相同的代码:

static async Task Main(string[] args)
{
    Console.WriteLine($"Start. Thread: {Thread.CurrentThread.ManagedThreadId}");
    await Task.Run(async () => await Task.Delay(1000));
    Console.WriteLine($"End. Thread: {Thread.CurrentThread.ManagedThreadId}");
}

导致不同的线程控制流:
开始。线程:1
结束。线程:5

我的猜测是,控制台应用程序具有与同步上下文不同的概念,并且不像WPF那样绑定到主“ UI”线程。但是我实际上正在努力寻找一些与此相关的明确信息。

1 个答案:

答案 0 :(得分:3)

简而言之,如果未设置SynchronizationContext.Current,则(在控制台应用程序中就是这种情况)。在ThreadPool上调用等待响应。

在Winforms / WPF上,实现了SynchronizationContext以将对Winforms controlToSendTo.BeginInvoke();或WPF Dispatcher.BeginInvoke();的响应排队。

参考:

  • Await, SynchronizationContext, and Console Apps(开发团队的博客文章by a member):

      

    但是有一种没有SynchronizationContext的常见应用程序:控制台应用程序。调用控制台应用程序的Main方法时,SynchronizationContext.Current将返回null。这意味着,如果您在控制台应用程序中调用异步方法,则除非您执行特殊操作,否则您的异步方法将不会具有线程亲和力:这些异步方法中的继续操作可能最终在任何地方运行。

  • Parallel Computing - It's All About the SynchronizationContextSynchronizationContext类的官方文档referenced from文章):

      

    默认情况下,控制台应用程序和Windows服务中的所有线程仅具有默认的SynchronizationContext

         

    ...

         

    图4 SynchronizationContext实现的摘要
      ...

    ╔═════════╦═══════════╦════════════╦════════════╦══════════╦══════════╗
    ║         ║ Specific  ║ Exclusive  ║ Ordered    ║ Send May ║ Post May ║
    ║         ║ Thread    ║ (Delegates ║ (Delegates ║ Invoke   ║ Invoke   ║
    ║         ║ Used to   ║ Execute    ║ Execute    ║ Delegate ║ Delegate ║
    ║         ║ Execute   ║ One at     ║ in Queue   ║ Directly ║ Directly ║
    ║         ║ Delegates ║ a Time)    ║ Order)     ║          ║          ║
    ╠═════════╬═══════════╬════════════╬════════════╬══════════╬══════════╣
    ║ ...     ║           ║            ║            ║          ║          ║
    ╠═════════╬═══════════╬════════════╬════════════╬══════════╬══════════╣
    ║ Default ║ No        ║ No         ║ No         ║ Always   ║ Never    ║
    ╚═════════╩═══════════╩════════════╩════════════╩══════════╩══════════╝