Console中的异步void方法不想触发

时间:2015-05-12 16:22:51

标签: c# console async-await

为什么我在运行以下程序时在控制台中看不到任何内容?

Screenshot for proof.

当我取消注释这两行时,我会看到两条完成消息(为什么不只是"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!"));
        }
    }
}

4 个答案:

答案 0 :(得分:1)

这很简单:

添加

Console.ReadLine(); // waits for a key to be pressed on form

之后

var bar = new Bar();

等待用户操作。

答案 1 :(得分:1)

正如@Servy所指出的那样,这是一种非确定性的行为 - 我无法在我的机器上得到它没有打印,你无法得到它打印

为什么它是非确定性的?这是因为:

  1. 任务创建为background threads
  2. 控制台有no synchronization context
  3. 这意味着您运行的任务及其继续(通过异步等待程序注册)都将在后台线程上运行,因此如果主线程(整个应用程序)在能够打印之前结束,则您赢得了'什么都看不见。

    为什么在第二种情况下会为您打印?再次 - 因为它是一种非确定性行为,取决于任务调度和操作系统状态。

答案 2 :(得分:1)

  

但是当我取消注释这两行时,为什么我会看到这两条消息?为什么不只是“Foo完成!” ?

您的代码在Main终止和线程池线程上的委托执行之间存在竞争条件,因此您的结果将是非确定性的。如果Task足够快地执行委托,您将看到两者。不能保证一个人会先完成另一个。

运行你的代码足够多次,你最终可能只会抓住“Foo Done”。

答案 3 :(得分:1)

当您同时取消注释时,您可能会幸运地看到"Bar Done!"

因为您正在运行Bar异步,所以主线程可能在它有机会写入控制台之前完成。添加Foo可能会减慢主线程的速度,使写入工作。

尝试等待DoWorkAsync

private class Bar { 
    public Bar() { 
        DoWorkAsync().Wait(); 
    } 

    private async Task DoWorkAsync()
   { 
       return await Task.Run(() => Console.WriteLine("Bar Done!")); 
   } 
}