-1
var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));

new Thread(async () =>
    {
        try
            {
                while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
                {
                    ... do some things
                }
            }
            catch (OperationCanceledException)
            {
            }
    })
    {
        IsBackground = true,
    }
.Start();

Every 5 minutes I have to do some things in the background thread. For some reason in some random time I get 300% cpu usage. Something wrong with my code? Thanks.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
andrey1567
  • 97
  • 1
  • 13
  • 1
    Just FYI `new Thread` is kind of useless here. Use `Task.Run`. – Guru Stron Apr 26 '23 at 14:44
  • 1
    Also _"300% CPU"_ is an interesting claim, how have you measured this? – Guru Stron Apr 26 '23 at 14:45
  • @GuruStron how about this? https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#avoid-using-taskrun-for-long-running-work-that-blocks-the-thread – andrey1567 Apr 26 '23 at 15:17
  • `await timer` - your code does not block the thread. – Guru Stron Apr 26 '23 at 15:19
  • 1
    The problem with `Thread` is the same as one which is mentioned in _"Don't use TaskCreationOptions.LongRunning with async code as this will create a new thread which will be destroyed after first await."_. – Guru Stron Apr 26 '23 at 15:21
  • I doubt that this will actually fix your problems though. I would argue that they are not present in the provided code. It is either in `... do some things` on in the code doing `new Thread`. – Guru Stron Apr 26 '23 at 15:35

1 Answers1

-1

Something wrong with my code?

Yes, there is something wrong with this code, but fixing it will not solve the CPU over-utilization problem. The wrong thing is that you pass an asynchronous delegate to the Thread constructor. The Thread class does not expect an async delegate in the constructor, so the delegate is async void, which is something to avoid. You can learn why this is pointless from the answer in this question:

You can fix this by replacing the new Thread(async () => with Task.Run(async () =>. The Task.Run method understands async delegates, and will give you back a Task that you can later await, or query for its completion and potential Exception. In case you want to keep the existing async void semantics, meaning that in case of an unhandled exception you want your program to crash, then replace the new Thread(async () => with ThreadPool.QueueUserWorkItem(async _ =>.

As for the reason for the CPU spikes, it is hidden in the ... do some things code. We don't know what this code does, so we can't help you fix it.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104