为什么控制台上没有打印任何内容?

问题描述 投票:0回答:3

我创建了 2 个打印 x 和 y 100 次的方法。我希望它们并发运行,并且我希望输出为 xxxyxyxyyyxyyxyx... 之类的。 它不打印任何东西。我在这里缺少一些逻辑吗?

using System;
using System.Threading.Tasks;

namespace ConsoleApplication32
{
    internal class Program
    {
        public static async Task<int> Print1()
        {
            await Task.Run(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.Write("x");
                }
            });

            return 1;
        }

        public static async Task<int> Print2()
        {
            await Task.Run(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.Write("y");
                }
            });

            return 1;
        }

        public static void Run()
        {
            Task<int> i = Print1();
            Task<int> k = Print2();
        }

        private static void Main(string[] args)
        {
            Run();
        }
    }
}
c# .net async-await
3个回答
12
投票

说明

我们需要调整一些事情才能获得所需的输出:

xxxxyxyxyyyxyyxyx

  1. Run
    方法不等待
    Task i
    Task k
    完成

    • 这意味着控制台应用程序将在两个
      Task
      完成之前关闭
    • 正如 Andrei Matracaru 在他的回答中提到的,如果添加
      Console.ReadLine()
      ,它将阻止控制台应用程序在字符串打印到屏幕上之前关闭。
    • 更优雅的解决方案是使用
      Task.WhenAll
      Task.WhenAll
      将允许代码屈服于其调用线程(在本例中为主线程),该线程不会冻结应用程序的 UI,并允许应用程序继续打印到屏幕,直到
      Task
      已完成完全的。对于一个简单的控制台应用程序来说,这似乎微不足道,但在构建任何用户交互应用程序(如移动或 Web 应用程序)时,永远不要锁定主线程至关重要;锁定主线程是导致应用程序“冻结”的原因。
    • Camilo Terevinto上面的答案推荐
      Task.WaitAll
      。这也是不好的做法,因为它也会冻结应用程序;
      Task.WaitAll
      不可等待,并且不能屈服于调用线程。
  2. Print1()
    Print2()
    永远不会屈服于主线程

    • 这些方法在后台线程上执行,但它们不包含
      await
       内部的 
      for loop
    • await
      内部需要一个
      for loop
      ,以允许CPU继续执行主线程,因为
      Console.Write()
      只能在主线程上打印到屏幕。

代码

using System;
using System.Threading.Tasks;

namespace ConsoleApplication32
{
    internal class Program
    {
        public static async Task<int> Print1()
        {
            for (int i = 0; i < 100; i++)
            {
                Console.Write("x");
                await Task.Delay(10);
            }

            return 1;
        }

        public static async Task<int> Print2()
        {
            for (int i = 0; i < 100; i++)
            {
                Console.Write("y");
                await Task.Delay(10);
            }

            return 1;
        }

        public static async Task Run()
        {
            var i = Print1();
            var k = Print2();

            await Task.WhenAll(i, k);
        }

        private static void Main(string[] args)
        {
            Task.Run(async () => await Run()).GetAwaiter().GetResult();
        }
    }
}

输出

xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxxyxyxyxy 按任意键继续...

C# 7.1 替代方案

C# 7.1 引入了

async Main
方法的功能。这意味着我们可以调整
Main
方法,如下所示:

    ...

    private static async Task Main(string[] args)
    {
        await Run();
    }
    ...

5
投票

尝试了你的代码并且工作得很好。您可能认为它不起作用,因为控制台窗口关闭得非常快。在 Main 中添加

Console.ReadLine()

private static void Main(string[] args)
{
    Run();
    Console.ReadLine();
}

3
投票

问题是您没有等待任务完成,因此程序正在终止(不再有同步代码阻塞)。

如果您希望任务同时运行,请执行以下操作:

public static void Run()
{
    Task<int> i = Print1();
    Task<int> k = Print2();
    Task.WaitAll(i, k);
}

等待此任务完成的另一种方法是执行以下操作:

public static async Task Run()
{
    Task<int> i = Print1();
    Task<int> k = Print2();
    await Task.WhenAll(i, k);
}

public static void Main(string[] args)
{
    Run().GetAwaiter().GetResult();
}
© www.soinside.com 2019 - 2024. All rights reserved.