Runtimes, Wakers, and the Reactor-Executor Pattern 210 } executor. block_on(async_main()); handles. into_iter(). for_each(|h| h. join(). unwrap()); } coroutine fn request(i: usize) { let path = format!("/{}/Hello World{i}", i * 1000); let txt = Http::get(&path). wait; let txt = txt. lines(). last(). unwrap_or_default(); println!(«{txt}»); } coroutine fn async_main() { println!("Program starting"); for i in 0..5 { let future = request(i); runtime::spawn(future); } } The machine I'm currently running has 12 cores, so when I create 11 new threads to run the same asynchronous tasks, I'll use all the cores on my machine. As you'll notice, we also give each thread a unique name that we'll use when logging so that it's easier to track what happens behind the scenes. Note While I use 12 cores, you should use the number of cores on your machine. If we increase this number too much, our OS will not be able to give us more cores to run our program in parallel on and instead start pausing/resuming the threads we create, which adds no value to us since we handle the concurrency aspect ourselves in an a^tsync runtime. Y ou'll have to do the same steps as we did in the last example: 1. Replace the code that's currently in main. rs with the preceding code. 2. Run corofy. /src/main. rs. 3. Copy everything from main_corofied. rs to main. rs and delete main_corofied. rs. 4. Fix the fact that corofy doesn't know we changed our futures to take waker: &Waker as an argument. The easiest way is to simply run cargo check and let the compiler guide you to the places we need to change.