作者:京东科技 贾世闻
Tokio 无疑是 Rust 世界中最优良的异步Runtime实现。非阻塞的个性带来了优异的性能,然而在理论的开发中咱们往往须要在某些状况下阻塞工作来实现某些性能。
咱们看看上面的例子
fn main(){ let max_task = 1; let rt = runtime::Builder::new_multi_thread() .worker_threads(max_task) .build() .unwrap(); rt.block_on(async { println!("tokio_multi_thread "); for i in 0..100 { println!("run {}", i); tokio::spawn(async move { println!("spawn {}", i); thread::sleep(Duration::from_secs(2)); }); } }); }
咱们期待的运行构造是通过异步工作打印出99个 “spawn i",但理论输入的后果大略这样
tokio_multi_threadrun 0run 1run 2.......run 16spawn 0run 17......run 99spawn 1spawn 2......spawn 29......spawn 58spawn 59
59执行完前面就没有输入了,如果把max_task设置为2,状况会好一点,然而也没有执行完所有的异步操作,也就是说在资源有余的状况下,Tokio会摈弃某些工作,这不合乎咱们的预期。那么能不能再达到了某一阀值的状况下阻塞一下,不再给Tokio新的工作呢。这有点相似线程池,当达达最大线程数的时候阻塞前面的工作待有开释的线程后再持续。
咱们看看上面的代码。
fn main(){ let max_task = 2; let rt = runtime::Builder::new_multi_thread() .worker_threads(max_task) .enable_time() .build() .unwrap(); let mut set = JoinSet::new(); rt.block_on(async { for i in 0..100 { println!("run {}", i); while set.len() >= max_task { set.join_next().await; } set.spawn(async move { sleep().await; println!("spawn {}", i); }); } while set.len() > 0 { set.join_next().await; } }); }
咱们应用JoinSet来治理派生进去的工作。set.join_next().await; 保障至多一个工作被执行实现。联合set的len,咱们能够在工作达到下限时阻塞工作派生。当循环完结,可能还有未实现的工作,所以只有set.len()大于0就期待工作完结。
输入大略长这样
running 1 testtokio_multi_threadrun 0run 1spawn 0run 2spawn 1......run 31spawn 30run 32spawn 31run 33......run 96spawn 95run 97spawn 96run 98spawn 97run 99spawn 98spawn 99
合乎预期,代码不多,有趣味的同学能够入手尝试一下。