I am launching 2 tasks , without await
-ing them , and one of them is depending on the other.
I am trying to understand why is the following snipped of code blocking.
public class Tasks {
EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.ManualReset);
public async Task Job1() {
Console.WriteLine("Finished job1");
handle.Set();
}
public async Task Job2() {
handle.WaitOne();
Console.WriteLine("Doing Job2 work");
}
}
class Program {
static async Task Main(string[] args) {
Tasks seq = new Tasks();
var t2 =seq.Job2();
var t1 =seq.Job1();
await Task.WhenAll(t1, t2);
Console.WriteLine("finished both");
}
}
If i create CPU-bound
tasks for both my tasks it works :
var t2=Task.Run(seq.Job2);
var t1=Task.Run(seq.Job1);
I have also tried to put both tasks in a separate task from the main thread and it still blocks:
var bigtask=Task.Run(async()=>{
var t2 =seq.Job2();
var t1 =seq.Job1();
});
If i launch a task without await-ing it isn't it almost the same as starting a new CPU-bound
task ? (Task.Run
)
Look at your compiler warnings; they will tell you exactly what's going wrong. Specifically, you're using async
without await
, so those methods will run synchronously.
Task.Run
executes the method on a thread pool thread, which prevents it from running synchronously.
If i launch a task without await-ing it isn't it almost the same as [using Task.Run]?
Every async
method starts executing synchronously; await
is the point at which it can behave asynchronously.
async
by itself doesn't use any threads (or the thread pool); it's more like a fancier syntax for callbacks. Task.Run
does use the thread pool.
To solve your underlying problem (having one task wait for another), the easiest approach is to pass the Task
returned from Job1
to the Job2
method, and have Job2
await
that task. If that's not possible, then you need an asynchronous kind of signal (not a blocking one like EventWaitHandle
). A one-time asynchronous signal is TaskCompletionSource<T>
; SemaphoreSlim
also supports asynchronous waits; and more complex coordination primitives are part of my AsyncEx library.