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
asyncwithoutawait, so those methods will run synchronously.Task.Runexecutes the method on a thread pool thread, which prevents it from running synchronously.Every
asyncmethod starts executing synchronously;awaitis the point at which it can behave asynchronously.asyncby itself doesn't use any threads (or the thread pool); it's more like a fancier syntax for callbacks.Task.Rundoes use the thread pool.To solve your underlying problem (having one task wait for another), the easiest approach is to pass the
Taskreturned fromJob1to theJob2method, and haveJob2awaitthat task. If that's not possible, then you need an asynchronous kind of signal (not a blocking one likeEventWaitHandle). A one-time asynchronous signal isTaskCompletionSource<T>;SemaphoreSlimalso supports asynchronous waits; and more complex coordination primitives are part of my AsyncEx library.