加入收藏 | 设为首页 | 会员中心 | 我要投稿 惠州站长网 (https://www.0752zz.com.cn/)- 办公协同、云通信、物联设备、操作系统、高性能计算!
当前位置: 首页 > 建站 > 正文

硬核!Rust异步编程方式重大升级:新版Tokio如何提升10倍性能详解

发布时间:2019-10-24 02:35:14 所属栏目:建站 来源:高可用架构
导读:副标题#e# 协程或者绿色线程是近年来经常讨论的话题。Tokio作为Rust上协程调度器实现的典型代表,其设计和实现都有其特色。本文是Tokio团队在新版本调度器发布后,对其设计和实现的经验做的总结,十分值得一读。 Tokio作为 Rust 语言的异步运行时,我们一直

综上所述:

  • 尽量减少同步操作总是好的
  • “任务窃取”是通用调度器的首选算法
  • 处理器间基本是相互独立的,但是“偷窃”操作时不可避免的需要一些同步操作

Tokio 0.1 调度器

2018年3月,Tokio 发布了其第一版基于“任务窃取”算法的调度器。但那个版本的实现中有一些瑕疵:

首先,I/O 型任务会被同时操作 I/O 选择器(epoll、kqueue、iocp等)的线程所执行;更多与 CPU 绑定的任务会进入线程池。在这种情况下,活跃态线程的数量应该是灵活的、动态的,所以(适时得)关闭空闲态线程是合理的。但是,在“任务窃取”调度器上执行所有异步任务时,始终保持少量的活跃态线程是更合理的。

其次,当时采用了基于 Chase-Lev deque 算法的队列,该算法后来被证明并不适合于调度独立的异步任务场景。

第三,实现过于复杂。由于代码中过多得使用 atomic,然而大部分情况下,mutex 是更好地选择。

最后,代码中有许多细小的低效设计和实现,但由于早期为保证 API 的稳定性,导致了一些技术债。

当然,随着 Tokio 新版的发布,我们收获了很多的经验教训,偿还了许多技术债,这着实是令人兴奋的!

下一代的 Tokio 调度器

现在我们深入解析一下新调度器的变更。

新的任务系统

首先,重要的亮点并不属于 Tokio 的一部分,但对达成我们的成就至关重要:std 包含了由 Taylor Cramer设计的新的任务系统。该系统给调度系统提供了钩子(hooks),方便调度器执行 Rust 异步任务,并且确实做得很好,比之前的版本更轻巧灵活。

Waker结构由资源保存,用于表示任务可运行并被推送到调度程序的运行队列中。在新的任务系统中,Waker结构过去是更大的,但指针宽度为两个指针。减小大小对于最小化复制Waker值的开销以及在结构中占用较少的空间非常重要,从而允许将更多关键数据放入高速缓存行中。自定义vtable设计可实现许多优化,这将在后面讨论。

更好的任务队列

任务队列是调度程序的核心,是最关键的组成部分。最初的tokio调度器使用crossbeam的deque实现,即单生产者、多消费者deque。任务从一端入队,从另一端出队。大多数情况下,入队线程会出队它,然而,其他线程偶尔会出队任务来“窃取”。deque包含一个数组和一组追踪头部和尾部的索引。当deque满了时,入队数据将导致存储空间增长。会分配一个新的、更大的数组,并将值移到新存储区中。

双端队列增长的能力要付出复杂性和运行成本。入队/出队操作必须考虑到这种情况。此外,在队列增长时,释放原始数组会带来额外的困难。在垃圾收集语言中,gc会释放它。然而rust不带GC,这意味着程序需要负责释放数组,但线程可能正在并发访问内存。Crossbeam对此的答案是采用基于代的回收策略。虽然开销并不是非常大,但确实在代码热路径中的增加了不小的开销。每当进入和退出临界区时,每个操作都必须是atomic RMW(读修改写)操作,以向其他线程发出信号。

(编辑:惠州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读