文盘Rust -- 用Tokio实现简易任务池

打印 上一主题 下一主题

主题 925|帖子 925|积分 2775

作者:京东科技 贾世闻
Tokio 无疑是 Rust 世界中最优秀的异步Runtime实现。非阻塞的特性带来了优异的性能,但是在实际的开发中我们往往需要在某些情况下阻塞任务来实现某些功能。
我们看看下面的例子
  1. fn main(){
  2.         let max_task = 1;
  3.         let rt = runtime::Builder::new_multi_thread()
  4.             .worker_threads(max_task)
  5.             
  6.             .build()
  7.             .unwrap();     
  8.         rt.block_on(async {
  9.             println!("tokio_multi_thread ");
  10.             for i in 0..100 {
  11.                 println!("run {}", i);     
  12.                 tokio::spawn(async move {
  13.                     println!("spawn {}", i);
  14.                     thread::sleep(Duration::from_secs(2));
  15.                 });
  16.             }
  17.         });
  18.     }
复制代码
我们期待的运行结构是通过异步任务打印出99个 “spawn i",但实际输出的结果大概这样
  1. tokio_multi_thread
  2. run 0
  3. run 1
  4. run 2
  5. .......
  6. run 16
  7. spawn 0
  8. run 17
  9. ......
  10. run 99
  11. spawn 1
  12. spawn 2
  13. ......
  14. spawn 29
  15. ......
  16. spawn 58
  17. spawn 59
复制代码
59执行完后面就没有输出了,如果把max_task设置为2,情况会好一点,但是也没有执行完所有的异步操作,也就是说在资源不足的情况下,Tokio会抛弃某些任务,这不符合我们的预期。那么能不能再达到了某一阀值的情况下阻塞一下,不再给Tokio新的任务呢。这有点类似线程池,当达达最大线程数的时候阻塞后面的任务待有释放的线程后再继续。
我们看看下面的代码。
  1. fn main(){
  2.         let max_task = 2;
  3.         let rt = runtime::Builder::new_multi_thread()
  4.             .worker_threads(max_task)
  5.             .enable_time()
  6.             .build()
  7.             .unwrap();     
  8.         let mut set = JoinSet::new();
  9.         rt.block_on(async {
  10.             for i in 0..100 {
  11.                 println!("run {}", i);
  12.                 while set.len() >= max_task {
  13.                     set.join_next().await;
  14.                 }
  15.                 set.spawn(async move {
  16.                     sleep().await;
  17.                     println!("spawn {}", i);
  18.                 });
  19.             }
  20.             while set.len() > 0 {
  21.                 set.join_next().await;
  22.             }
  23.         });
  24.     }
复制代码
我们使用JoinSet来管理派生出来的任务。set.join_next().await; 保证至少一个任务被执行完成。结合set的len,我们可以在任务达到上限时阻塞任务派生。当循环结束,可能还有未完成的任务,所以只要set.len()大于0就等待任务结束。
输出大概长这样
  1. running 1 test
  2. tokio_multi_thread
  3. run 0
  4. run 1
  5. spawn 0
  6. run 2
  7. spawn 1
  8. ......
  9. run 31
  10. spawn 30
  11. run 32
  12. spawn 31
  13. run 33
  14. ......
  15. run 96
  16. spawn 95
  17. run 97
  18. spawn 96
  19. run 98
  20. spawn 97
  21. run 99
  22. spawn 98
  23. spawn 99
复制代码
符合预期,代码不多,有兴趣的同学可以动手尝试一下。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

愛在花開的季節

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表