控制台中的异步无效方法不想触发
Async void method in Console doesn't want to fire
为什么我在运行下面的程序时在控制台中看不到任何东西?
当我取消注释这两行时,我看到了两条完成消息(为什么不仅 "Foo Done!"
?)
class Program
{
static void Main(string[] args)
{
//var foo = new Foo();
var bar = new Bar();
}
private class Foo
{
public Foo()
{
DoWork();
}
private void DoWork()
{
Console.WriteLine("Foo Done!");
}
}
private class Bar
{
public Bar()
{
DoWorkAsync();
}
private async void DoWorkAsync()
{
await Task.Run(() => Console.WriteLine("Bar Done!"));
}
}
}
就这么简单:
只需添加
Console.ReadLine(); // waits for a key to be pressed on form
调用后
var bar = new Bar();
等待用户操作。
正如@Servy 所指出的那样,这是一种不确定的行为 - 我无法在我的机器上得到它未打印,你无法得到它打印在你身上。
为什么它是非确定性的?因为:
- 任务创建为 background threads
- 控制台有 no synchronization context
这意味着您 运行 的任务及其延续(通过异步等待程序注册)都将 运行 在后台线程上,因此如果主线程(整个应用程序)在它之前结束能够打印,你什么也看不到。
为什么在第二种情况下为您打印?再次 - 因为它是一种取决于任务调度和操作系统状态的非确定性行为。
But why I see both messages when I uncomment both lines? Why not only "Foo done!" ?
您的代码在 Main
的终止和线程池线程上的委托执行之间存在竞争条件,因此您的结果将是不确定的。如果 Task
执行委托的速度足够快,您会看到两者。不能保证一个会比另一个先完成。
运行 你的代码足够多次,你最终可能只会抓到 "Foo Done"。
当您都取消注释时,您可能会很幸运地看到 "Bar Done!"
。
因为你是 运行 Bar
异步主线程可能在它有机会写入控制台之前完成。添加 Foo
可能会减慢主线程的速度,足以让写入工作正常进行。
尝试等待 DoWorkAsync
private class Bar {
public Bar() {
DoWorkAsync().Wait();
}
private async Task DoWorkAsync()
{
return await Task.Run(() => Console.WriteLine("Bar Done!"));
}
}
为什么我在运行下面的程序时在控制台中看不到任何东西?
当我取消注释这两行时,我看到了两条完成消息(为什么不仅 "Foo Done!"
?)
class Program
{
static void Main(string[] args)
{
//var foo = new Foo();
var bar = new Bar();
}
private class Foo
{
public Foo()
{
DoWork();
}
private void DoWork()
{
Console.WriteLine("Foo Done!");
}
}
private class Bar
{
public Bar()
{
DoWorkAsync();
}
private async void DoWorkAsync()
{
await Task.Run(() => Console.WriteLine("Bar Done!"));
}
}
}
就这么简单:
只需添加
Console.ReadLine(); // waits for a key to be pressed on form
调用后
var bar = new Bar();
等待用户操作。
正如@Servy 所指出的那样,这是一种不确定的行为 - 我无法在我的机器上得到它未打印,你无法得到它打印在你身上。
为什么它是非确定性的?因为:
- 任务创建为 background threads
- 控制台有 no synchronization context
这意味着您 运行 的任务及其延续(通过异步等待程序注册)都将 运行 在后台线程上,因此如果主线程(整个应用程序)在它之前结束能够打印,你什么也看不到。
为什么在第二种情况下为您打印?再次 - 因为它是一种取决于任务调度和操作系统状态的非确定性行为。
But why I see both messages when I uncomment both lines? Why not only "Foo done!" ?
您的代码在 Main
的终止和线程池线程上的委托执行之间存在竞争条件,因此您的结果将是不确定的。如果 Task
执行委托的速度足够快,您会看到两者。不能保证一个会比另一个先完成。
运行 你的代码足够多次,你最终可能只会抓到 "Foo Done"。
当您都取消注释时,您可能会很幸运地看到 "Bar Done!"
。
因为你是 运行 Bar
异步主线程可能在它有机会写入控制台之前完成。添加 Foo
可能会减慢主线程的速度,足以让写入工作正常进行。
尝试等待 DoWorkAsync
private class Bar {
public Bar() {
DoWorkAsync().Wait();
}
private async Task DoWorkAsync()
{
return await Task.Run(() => Console.WriteLine("Bar Done!"));
}
}