我正试图弄清楚如何在C#中启动异步主方法。为此,我想创建一个与异步主线程相同的新线程示例。
这就是在没有异步的情况下完成的方式:
class Program
{
public static void Main(string[] args)
{
Thread t = new Thread(Main2)
{ IsBackground = false };
t.Start();
}
public static void Main2()
{
Console.WriteLine("Helloooo");
Thread.Sleep(1000);
Console.WriteLine("Woooorld");
}
}
如果我运行上面的代码,将打印以下内容:
Helloooo
Woooorld
您可以看到,我没有添加t.Join()
,这是因为t是前台线程。但是,如果尝试对async进行同样的操作,则会发生以下情况:
class Program
{
public static void Main(string[] args)
{
Thread t = new Thread(Main2)
{ IsBackground = false };
t.Start();
}
// Can't use "public static async Task main2"
// because you need to pass in a void method to a new thread
public static async void Main2()
{
Console.WriteLine("Helloooo");
await Task.Delay(1000);
Console.WriteLine("Woooorld");
}
}
仅
Helloooo
打印,并且程序退出,即使新线程是前台线程。现在我明白了这里发生的事情,当新线程到达await Task.Delay(1000);
时,它启动一个状态机,并释放线程用于其他事情。我想知道的是,为了让我原来的线程消亡,让我的新线程接管,我必须改变什么。我想了解异步/等待链是如何启动的的。
一篇关于C#7.1的文章说:
";通过允许入口点返回Task/Task并标记为async,允许在应用程序的Main/entrypoint方法中使用wait">
public static void Main()
{
MainAsync().GetAwaiter().GetResult();
}
private static async Task MainAsync()
{
... // Main body here
}
";我们可以消除对这个样板的需要,并通过允许Main本身是异步的,从而使waiting可以在其中使用,使其更容易开始
来源:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.1/async-main
正如你所看到的,它们并不是单独的线程,而是";"阻塞";直到MainAsync返回任务IsCompleted。
发生这种情况是由于以下因素的组合:
- 在Console应用程序中,
SynchronizationContext.Current
not被设置 - 如果未设置
SynchronizationContext.Current
,则在ThreadPool线程上调用等待响应(例如,在您的示例中打印"Woooorld"( - ThreadPool线程是后台线程