Asynchronous code, coroutines, async/await, parallelising problems is my deep interest and I blog about it everyday.
I think the easiest way to parallelise is to shard your data per thread and treat your multithreaded (or multimachine) architecture as a tree - not a graph - where dataflow doesn't need to pass between tree branches. This is similar to the Rust's "no interior mutabiliy" and Rust data structures pattern.
My machine can lock and unlock 61570760 times a second. But it can count to 2 billion in 1 second. So locks are expensive.
I recently worked at parallelising the A* graph search algorithm that I'm using for code generation/program synthesis.
For 16 processes it takes 35 seconds to synthesise a program but with 3 processes it takes 21 seconds. I think my approach to parallelising A* needs a redesign.
We hit Amdahl's law when it comes to parallelising. I need to split up my problem into spaces that don't require synchronization/serialisation.
EDIT: I've mentioned this whitepaper before ("Scalability! But at what COST?") but this whitepaper would be useful reading of anybody working on multithreaded or distributed systems. In summary: single threaded programs can easily be faster and more performant (wall clock time) than multithreaded/multimachine distributed machines, but they don't scale.
https://www.usenix.org/system/files/conference/hotos15/hotos...