假设我想用 Tokio 同时下载两个网页......
我可以用以下方法来实现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());
}
Run Code Online (Sandbox Code Playgroud)
或者我可以通过以下方式实现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());
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,两个请求都是同时发生的。但是,在第二种情况下,两个请求在同一任务中运行,因此在同一线程上运行。
所以,我的问题是:
tokio::join!()超过有优势吗tokio::spawn()?我猜生成一个新任务的开销非常小,但真的是这样吗?
Pet*_*all 21
差异取决于您配置运行时的方式。将在同一个任务中tokio::join!同时运行任务,同时为每个任务创建一个新任务。tokio::spawn
在单线程运行时,这些实际上是相同的。在多线程运行时,使用tokio::spawn!两次类似的操作可能会使用两个单独的线程。
从文档中tokio::join!:
通过在当前任务上运行所有异步表达式,这些表达式可以并发运行,但不能并行运行。这意味着所有表达式都在同一线程上运行,如果一个分支阻塞该线程,则所有其他表达式将无法继续。如果需要并行性,请使用 生成每个异步表达式
tokio::spawn并将连接句柄传递给join!。
对于 IO 密集型任务,例如下载网页,您不会注意到差异;大部分时间将花费在等待数据包上,并且每个任务可以有效地交错其处理。
tokio::spawn当任务更多地受 CPU 限制并且可能相互阻塞时使用。
kmd*_*eko 13
我通常会从另一个角度来看待这个问题;我为什么要使用tokio::spawnover tokio::join?生成一个新任务比加入两个 future 有更多的限制,这个'static要求可能非常烦人,因此不是我的首选。
除了产生任务的成本(我认为这是相当微不足道的)之外,还有在原始任务完成时发出信号的成本。我也认为这是微不足道的,但您必须在您的环境和异步工作负载中测量它们,看看它们是否确实产生影响。
但你是对的,使用两个任务的最大好处是它们有机会并行工作,而不仅仅是同时工作。但另一方面,async它最适合 I/O 密集型工作负载,其中存在大量等待,并且根据您的工作负载,缺乏并行性可能不会产生太大影响,具体取决于您的工作负载。
总而言之,tokio::join它使用起来更好、更灵活,我怀疑技术差异会对性能产生影响。但一如既往:测量!
| 归档时间: |
|
| 查看次数: |
22236 次 |
| 最近记录: |