-1

I have a construct like this:

Func<object> func = () =>
{
    foreach(var x in y)
    {
        ...
        Task.Delay(100).Wait();
    }
    return null;
}
var t = new Task<object>(func);
t.Start(); // t is never awaited or waited for, the main thread does not care when it's done.
...

So basically i create a function func that calls Task.Delay(100).Wait() quite a few times. I know the use of .Wait() is discouraged in general. But I want to know if there are concrete performance losses for the displayed case.

The .Wait() calls happen in a separate Task, that is completely independend from the main Thread, i.e. it is never awaited or waited for. I am curious what happens when I call Wait() this way, and what happens on the processor of my machine. During the 100 ms that are waited, can the processor core execute another thread, and returns to the Task after the time has passed? Or did I just produce a busy waiting procedure, where my CPU "actively does nothing" for 100 ms, thus slowing down the rest of my program?

Does this approach have any practical downsides when compared to a solution where i make it an async function and call await Task.Delay(100)? That would be an option for me, but I would rather not go for it if it is reasonably avoidable.

TostMaster
  • 164
  • 2
  • 9
  • 3
    Yes. `Wait()` blocks the thread. `Task.Delay()` doesn't. A task isn't a thread, it represents a *promise* that something will complete in the *future*. That something may run on a threadpool thread or not. There's never any good reason to create cold tasks and call `.Start()` – Panagiotis Kanavos Jun 14 '21 at 11:52
  • 2
    `.Wait()` will always block the current thread. `Task.Delay()` on the other hand doesn't use a thread at all. It uses a timer that sets a `TaskCompletionSource` to `Complete` after the timeout expires. The question's code wastes a threadpool thread doing nothing but wait. And since waiting typically start by a spinwait, this code could end up blocking a CPU core until the OS decides to reschedule that thread – Panagiotis Kanavos Jun 14 '21 at 11:57
  • 1
    `but I would rather not go for it if it is reasonably avoidable` why? That's the reason for this? – Panagiotis Kanavos Jun 14 '21 at 11:59
  • [Race your horses](https://ericlippert.com/2012/12/17/performance-rant/) – Damien_The_Unbeliever Jun 14 '21 at 12:02
  • 3
    @PanagiotisKanavos You should post that as an answer – Charlieface Jun 14 '21 at 13:11
  • @Charlieface see [Answerers who only use comments](https://meta.stackoverflow.com/questions/253045/answerers-who-only-use-comments). You could consider reposting the comment as a Community Wiki answer. FYI flagging such comments is ineffective, and the flags get declined. Moderators cannot convert comments into answers. They can only delete comments, but they don't do it for comments that attempt to answer the question, because that could be discarding potentially valuable information. – Theodor Zoulias Jun 14 '21 at 17:48

1 Answers1

1

There are concrete efficiency losses because of the inefficient use of threads. Each thread requires at least 1 MB for its stack, so the more threads that are created in order to do nothing, the more memory is allocated for unproductive purposes.

It is also possible for concrete performance losses to appear, in case the demand for threads surpasses the ThreadPool availability. In this case the ThreadPool becomes saturated, and new threads are injected in the pool in a conservative (slow) rate. So the tasks you create and Start will not start immediately, but instead they will be entered in an internal queue, waiting for a free thread, either one that completed some previous work, or an new injected one.

Regarding your concerns about creating busy waiting procedures, no, that's not what happening. A sleeping thread does not consume CPU resources.

As a side note, creating cold Tasks using the Task constructor is an advanced technique that's only used in special occasions. The common way of creating delegate-based tasks is through the convenient Task.Run method, that returns hot (already started) tasks.

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