|
Tokio无疑是Rust世界中最优秀的异步Runtime实现。非阻塞的特性带来了优异的性能,但是在实际的开发中我们往往需要在某些情况下阻塞任务来实现某些功能。我们看看下面的例子fnmain(){letmax_task=1;letrt=runtime::Builder::new_multi_thread().worker_threads(max_task).build().unwrap();rt.block_on(async{println!("tokio_multi_thread");foriin0..100{println!("run{}",i);tokio::spawn(asyncmove{println!("spawn{}",i);thread::sleep(Duration::from_secs(2));});}});}我们期待的运行结构是通过异步任务打印出99个“spawni",但实际输出的结果大概这样tokio_multi_threadrun0run1run2.......run16spawn0run17......run99spawn1spawn2......spawn29......spawn58spawn5959执行完后面就没有输出了,如果把max_task设置为2,情况会好一点,但是也没有执行完所有的异步操作,也就是说在资源不足的情况下,Tokio会抛弃某些任务,这不符合我们的预期。那么能不能再达到了某一阀值的情况下阻塞一下,不再给Tokio新的任务呢。这有点类似线程池,当达达最大线程数的时候阻塞后面的任务待有释放的线程后再继续。我们看看下面的代码。fnmain(){letmax_task=2;letrt=runtime::Builder::new_multi_thread().worker_threads(max_task).enable_time().build().unwrap();letmutset=JoinSet::new();rt.block_on(async{foriin0..100{println!("run{}",i);whileset.len()>=max_task{set.join_next().await;}set.spawn(asyncmove{sleep().await;println!("spawn{}",i);});}whileset.len()>0{set.join_next().await;}});}我们使用JoinSet来管理派生出来的任务。set.join_next().await;保证至少一个任务被执行完成。结合set的len,我们可以在任务达到上限时阻塞任务派生。当循环结束,可能还有未完成的任务,所以只要set.len()大于0就等待任务结束。输出大概长这样running1testtokio_multi_threadrun0run1spawn0run2spawn1......run31spawn30run32spawn31run33......run96spawn95run97spawn96run98spawn97run99spawn98spawn99符合预期,代码不多,有兴趣的同学可以动手尝试一下。-end-
|
|