0

So, I have created an automation script performs a task every minute, on the minute (I want the task to be ran at the :00 second of each minute). As a test, the function that I am calling every minute just writes to console and to a text file that it has ran and at which time it has ran.

I don't know anything about resource usage of apps and how to reduce it, but for some reason this application is using around 17% of my CPU on an i7 8750h cpu.

The entire code for the script is as follows:

Logger.WriteLine("Program starting... @ " + DateTime.Now.ToString("HH:mm:ss"));

 static void TestTask()
{
    string currentTime = DateTime.Now.ToString("HH:mm:ss");
    Logger.WriteLine("Test task ran at: " + currentTime);

}

// This currently runs forever, as there is no boolean condition evaluated to false to break the while loop (which is expected behavior)
while (true)
{   
    // Evyer minute on the minute 
    if (DateTime.Now.Second == 0)
    {
        TestTask();
        Thread.Sleep(1000);
    }
}

The Logger.WriteLine class is a custom class I created that essentially acts the same as Console.WriteLine as it prints the string to the console, but it also adds it to a stringbuilder that then gets written using stringwriter to a .txt file on my desktop. Could this be the issue?

I also tried creating the exact same program in Python, and it uses the same amount of CPU usage. Both .exe versions of the program use about 5mb of memory which is fine for me, but its just the CPU usage that I would like to reduce.

Anyone know anything I could do? Thanks!

mv1999
  • 45
  • 6
  • 1
    Does this answer your question? [C# program using up too much CPU?](https://stackoverflow.com/questions/10070869/c-sharp-program-using-up-too-much-cpu) – gunr2171 Nov 14 '22 at 14:44
  • 1
    Do not use `Thread.Sleep` ... – Selvin Nov 14 '22 at 14:45
  • 5
    Presumably you intended to move that `Thread.Sleep` to *outside* the condition. It would still be busy waiting, mind you, and it would still not work correctly (because the wait is not exactly one second, there is a very real risk of missing "the" 0 second), but it would not spin incessantly waiting for the magic second to hit. – Jeroen Mostert Nov 14 '22 at 14:47
  • 3
    98% of the time (59/60) that loop will be busy spinning without any sleeps, which will be using a LOT of CPU. – Matthew Watson Nov 14 '22 at 14:49
  • If you are on Windows and you want to execute something with a schedule, you can look into Windows Task Scheduler. In there you can schedule your program to run every X seconds and Windows will take care of the rest. – Izanagi Nov 14 '22 at 15:00
  • 1
    Unrealated: _"The Logger.WriteLine class is a custom class I created"_ - no. Don't. dotnet has an ok-to-use logging API and there are a few excellent logging frameworks. There is _no need_ (most of the time) to bother with any of this yourself. – Fildor Nov 14 '22 at 15:20

2 Answers2

4

To answer the question in the title

The code you posted will use pretty much 100% of a CPU core because for 59 out of the 60 seconds in a minute, all it does is evaluate whether true == true and whether the second component of DateTime.Now is 0, as fast as possible. The call to Thread.Sleep(1000) only occurrs in the 0th second.

A Core i7-8750H is a 6 core CPU, so divide 100% by 6 and you get (roughly) 17% overall utilisation. The result was the same in Python because the logic is exactly the same.

As for what you ought to do about it

There are numerous ways to accomplish the goal of a task that runs once a minute depending on the system you're working with. On Windows, you could use Windows Task Scheduler, on Unix-likes you could use cron, on macOS you could use launchd. If this is a sub-component of an app that needs to run in the background of that app, perhaps start here. Thread.Sleep() is not the recommended way to go about this.

madmonk46
  • 421
  • 3
  • 10
2

It's using up so much of your CPU because it's constantly looping round checking if it's the 1st second of the minute.

Thread.Sleep is only hit on the 1st second of each minute.

Moving Thread.Sleep outside of the if statement (but still within the while loop) and reducing the duration would improve it:

while (true)
{   
    // Every minute on the minute 
    if (DateTime.Now.Second == 0)
    {
        TestTask();
    }

    Thread.Sleep(500);
}

It would be better yet to use a wait or a timer.

YungDeiza
  • 3,128
  • 1
  • 7
  • 32
  • 1
    Thread.Sleep pauses the software thread. It is not using the CPU. – IamDOM Nov 14 '22 at 15:18
  • @YungDeiza Wow thanks! Somehow by doing that and putting the threat.sleep outside of the if statement, it reduces CPU usage drastically and now the program sits at 0% CPU usage. – mv1999 Nov 14 '22 at 15:19
  • 1
    @mv1999 because the thread.sleep is actually getting hit and your code is just sitting there waiting while the CPU is free. – IamDOM Nov 14 '22 at 15:20
  • 3
    @mv1999 Please: Make sure you understand _**why**_ it did that. – Fildor Nov 14 '22 at 15:22
  • 2
    @Fildor yes that's the important part - it's because by moving the sleep it gets executed on every run of the loop rather just when it's the first second of each minute. Updated answer to make that clearer. – YungDeiza Nov 14 '22 at 15:40
  • 1
    @YungDeiza Thank you, I think I understand. By putting the thread.sleep rather than running every time the while loop cycles (which I think is above 10,000 times per second as I did a test to print to a text file every time the while loop was cycled, which resulted in over 10k lines of text), it now runs after the specified time to wait - which I have set at 1000 milliseconds (1 second). Thank you once again everyone for the help and input! – mv1999 Nov 15 '22 at 08:53