控制台应用程序中的高CPU使用率

3
我希望能够在我的控制台应用程序中不断等待按下键组合,但目前的方法似乎在运行过程中使用了大量CPU。 对于这样一个基本的任务,感觉应该有更好的方法来完成,但我不确定是什么,我使用dotTrace对我的应用程序进行了分析,发现唯一的热点是下面的代码。

enter image description here

while (true)
{
    if (!Console.KeyAvailable)
    {
        continue;
    }

    var input = Console.ReadKey(true);

    if (input.Modifiers != ConsoleModifiers.Control)
    {
        continue;
    }

    if (input.Key == ConsoleKey.S)
    {
        Server?.Dispose();
    }
}

2
你正在经历“忙等待”:https://zh.wikipedia.org/wiki/%E5%BF%99%E7%AD%89%E5%8D%A0%E7%94%A8 - C-Otto
3
Console.ReadKey 会阻塞直到有按键输入,所以我认为你不需要使用 if(!Console.KeyAvailable) continue; 来进行判断。 - Maximilian Gerhardt
你用的是哪个代码编辑器,如果可以问一下的话? - Amr Elgarhy
@AmrElgarhy 我使用的IDE是Visual Studio,但问题中的图像是C#分析器(dottrace)的快照。 - ropuxil
@MaximilianGerhardt 感谢您的帮助,这将CPU使用率从大约20-30%降至3%。 - ropuxil
显示剩余2条评论
5个回答

3

如果您不介意使用标准的 Ctrl+C 退出程序,而不是 Ctrl+S,则可以使用简单的 ReadKey。并确保设置了 TreatControlCAsInput,否则应用程序将会被强制关闭。

  static void Main(string[] args)
  {
     // important!!!
     Console.TreatControlCAsInput = true;

     while (true)
     {
        Console.WriteLine("Use CTRL+C to exit");
        var input = Console.ReadKey();

        if (input.Key == ConsoleKey.C && input.Modifiers == ConsoleModifiers.Control)
        {
           break;
        }
     }

     // Cleanup
     // Server?.Dispose();
  }

谢谢,这正是我所需要的! - ropuxil

2

不要循环观看此内容,使用keypress事件来检查每次按键。

这意味着你只需要检查每次按键一次。

编辑: 我错过了控制台应用程序部分,但你可以像这样读取行:

来自:https://www.dotnetperls.com/console-readline

using System;

class Program
{
    static void Main()
    {
        while (true) // Loop indefinitely
        {
            Console.WriteLine("Enter input:"); // Prompt
            string line = Console.ReadLine(); // Get string from user
            if (line == "exit") // Check string
            {
                break;
            }
            Console.Write("You typed "); // Report output
            Console.Write(line.Length);
            Console.WriteLine(" character(s)");
        }
    }
}

你会在控制台应用程序中如何实现这个? - Amr Elgarhy
控制台应用程序中没有事件,您是在谈论其他事情吗?如果是,请给出一个例子。 - ropuxil

1
不需要忙等待。 Console.ReadKey() 会阻塞直到有按键可用,基本上没有 CPU 使用率。因此,您无需一遍又一遍地检查 Console.KeyAvailable
while (true)
{
    // DO NOT INTERCEPT KEY PRESSES! 
    //IF CTRL+S IS FORWARDED TO THE CONSOLE APP, WEIRD THINGS WILL HAPPEN.
    var input = Console.ReadKey(false);

    if (input.Modifiers != ConsoleModifiers.Control)
    {
        continue;
    }

    if (input.Key == ConsoleKey.S)
    {
        Server?.Dispose();
    }
}

你试过这个吗?在我的Win 10电脑上,Ctrl+S不能触发ReadKey。 - Euphoric
@Euphoric 不是,我会检查一下。如果是真的,则 OP 有一个普遍性问题,即无论等待多久都无法读取该键。 - Maximilian Gerhardt
@Euphoric 拦截是问题所在。将其设置为“false”即可解决所有问题。之前,“Ctrl+C”也会终止程序.. - Maximilian Gerhardt

0

我认为你应该使用Thread.Sleep

 while (true)
        {
            Thread.Sleep(100);
            if (!Console.KeyAvailable)
            {
                continue;
            }

            var input = Console.ReadKey(true);

            if (input.Modifiers != ConsoleModifiers.Control)
            {
                continue;
            }

            if (input.Key == ConsoleKey.S)
            {
                Server?.Dispose();
            }

        }

0

在完成Main(string[] args)之前,你只需要这个。

private static void Main(string[] args)
{
     //call method for daemon before while
     while (true)
     {
          Thread.Sleep(1000);
     }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,