Home > database >  Difference between Task.Start and using discard
Difference between Task.Start and using discard

Time:01-05

I have a Task that does not return a result, and no other code is dependent on it completing, like this:

private async Task PerformMyTaskAsync(CancellationToken CancellationToken)
{
    bool IsComplete = false;
    while (!IsComplete && !CancellationToken.IsCancellationRequested)
    {
        //Do stuff until Complete or Cancelled
    }
}

I have be using the discard to run it, like this:

_ = PerformMyTaskAsync(CancellationToken);

which works OK, but recently I discovered Task.Start. I know using Task.Start gives me the option of monitoring the task (if I store the result), but in this case, is there any difference between discard and this?

PerformMyTaskAsync(CancellationToken).Start();

Is it better practice to use discard as it's the newer feature?

CodePudding user response:

PerformMyTaskAsync(CancellationToken).Start() doesn't do what you want, so: don't do that! PerformMyTaskAsync(CancellationToken) will return an initialized working operation - it has already been started, because you just did that - calling .Start() will throw InvalidOperationException citing "Start may not be called on a promise-style task".

Discard itself doesn't do anything except tell the compiler "I meant to do this", which is basically just a way of saying "I don't want to await this" to suppress a compiler warning (CS4014 "Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call."). You can do that with the result of Task.Run, too - and should do in exactly the same scenarios.

So the real question here is Task.Run vs direct invoke; for that, the main difference is "how much of it runs now?". When invoking it directly, it will run on the current thread until the first incomplete await - at which point the async machinery kicks in. That can mean it runs to completion, and with a while loop could mean it effectively runs forever (for example if the loop incorrectly uses Thread.Sleep() instead of Task.Delay() for pausing). If you don't want any of it to run on the current thread, or you want it to be very clear that this is a parallel execution: use Task.Run:

_ = Task.Run(() => PerformMyTaskAsync(CancellationToken));

CodePudding user response:

Both _ = PerformMyTaskAsync(CancellationToken); and var task = PerformMyTaskAsync(CancellationToken); are identical, the only difference is that _ (discard) suppresses the warning because it is not awaited if you use PerformMyTaskAsync(CancellationToken);.

You do not need PerformMyTaskAsync(CancellationToken).Start(); to call an asynchronous method. Task is already started when you call the method. If you do not want to store the result ( awaitable task), you can simply use PerformMyTaskAsync(CancellationToken);

  • Related