I think in a lot of cases the async programming model is easier to work with than the thread programming model. In a sense it’s declarative vs procedural programming over again. With threads you have to identify parallelism opportunities at write time, and if you plan poorly you can end up with low core efficiency. With async programming you break your execution up into a graph of inputs and outputs and let your async scheduler dynamically bin-pack everything, paying an overhead for consistently high core efficiency without having to think about it or change your code very much.