ropuxil
ropuxil

Reputation: 131

High CPU usage in console application

I want to constantly wait for a key combination to be pressed in my console application, but the way I am currently doing it seems to use a lot of CPU while the process is running.

For such a basic task it feels like there should be a better way to do this, but I'm unsure of what that is, I profiled my application with dotTrace and found that the only hot spot was this code below.

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();
    }
}

Upvotes: 3

Views: 3248

Answers (5)

Derek Menendez
Derek Menendez

Reputation: 27

You only need this before finish Main(string[] args)

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

Upvotes: 0

Maximilian Gerhardt
Maximilian Gerhardt

Reputation: 5353

No busy waiting is needed. Console.ReadKey() will block until there is a key press available, with basically no CPU usage. Thus, you don't need to check Console.KeyAvailable over and over again.

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();
    }
}

Upvotes: 1

Euphoric
Euphoric

Reputation: 12849

If you are fine using standard Ctrl+C for exit instead of Ctrl+S you can use simple ReadKey. And make sure TreatControlCAsInput is set, oterwise, the application will just be killed.

  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();
  }

Upvotes: 3

Mark Redman
Mark Redman

Reputation: 24515

Instead of watching this in a loop, use the keypress event to check each time a key is pressed.

This means you only check once for each key press.

Edit: I missed the console app part but you can read the line like this:

from: 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)");
        }
    }
}

Upvotes: 2

Alexandr Kudryashov
Alexandr Kudryashov

Reputation: 631

I think you should use 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();
            }

        }

Upvotes: 0

Related Questions