Let's say I want to download two web pages concurrently with Tokio...
Either I could implement this with tokio::spawn()
:
async fn v1() {
let t1 = tokio::spawn(reqwest::get("https://example.com"));
let t2 = tokio::spawn(reqwest::get("https://example.org"));
let (r1, r2) = (t1.await.unwrap(), t2.await.unwrap());
println!("example.com = {}", r1.unwrap().status());
println!("example.org = {}", r2.unwrap().status());
}
Or I could implement this with tokio::join!()
:
async fn v2() {
let t1 = reqwest::get("https://example.com");
let t2 = reqwest::get("https://example.org");
let (r1, r2) = tokio::join!(t1, t2);
println!("example.com = {}", r1.unwrap().status());
println!("example.org = {}", r2.unwrap().status());
}
In both cases, the two requests are happening concurrently. However, in the second case, the two requests are running in the same task and therefore on the same thread.
So, my questions are:
tokio::join!()
over tokio::spawn()
?I'm guessing there's a very small overhead to spawning a new task, but is that it?
I would typically look at this from the other angle; why would I use tokio::spawn
over tokio::join
? Spawning a new task has more constraints than joining two futures, the 'static
requirement can be very annoying and as such is not my go-to choice.
In addition to the cost of spawning the task, that I would guess is fairly marginal, there is also the cost of signaling the original task when its done. That I would also guess is marginal but you'd have to measure them in your environment and async workloads to see if they actually have an impact or not.
But you're right, the biggest boon to using two tasks is that they have the opportunity to work in parallel, not just concurrently. But on the other hand, async
is most suited to I/O-bound workloads where there is lots of waiting and, depending on your workload, is probably unlikely that this lack of parallelism would have much impact.
All in all, tokio::join
is a nicer and more flexible to use and I doubt the technical difference would make an impact on performance. But as always: measure!