Tokio 0.1.8 包含多项增量改进

2018年8月24日

新版本的 Tokio 发布了,虽然比我最初希望的时间晚了一些(总是这样),但还是发布了。此版本除其他功能外,还包括一组新的 API,允许从异步上下文执行文件系统操作、并发改进、定时器改进以及更多内容(包括错误修复,请务必更新!)。

自从上一篇文章以来已经有一段时间了。虽然没有重大的功能发布,但这并不意味着我们一直闲着。在过去的几个月里,新的 crates 已经发布,其中包含许多增量改进。这些改进中有许多是由社区贡献的,所以我认为有必要重点介绍一下。

文件系统 API

tokio-fs 的初始版本更像是一个存根,而不是完整的实现。它只包含基本的文件系统操作。

最新版本包含了大多数文件系统 API 的 非阻塞版本。这项了不起的工作主要由 @griff 在一个 史诗般的 PR 中以及 @lnicola 在一系列较小的 PR 中贡献,但许多其他人也参与了帮助审查和改进 crate。

感谢以下人员:@dekellum@matsadler@debris@mati865@lovebug356@bryanburgers@shepmaster

并发改进

在过去的几个月里,@stjepang 一直在努力改进 Tokio 中与并发相关的部分。一些亮点:

  • #459 - 修复线程唤醒中的竞争条件
  • #470 - 改进 worker spinning
  • #517 - 提高 reactor 中使用的 RW Lock 的可扩展性。
  • #534 - 改进 work-stealing 运行时的 “stealing” 部分。

当他在城里参加 Rustconf 时,我们还进行了一次愉快的交流,我对他未来的工作感到兴奋。

当然,还要感谢所有的 crossbeam 工作。Tokio 非常依赖它。

current_thread::Runtime

自最初由 @vorner@kpp 引入以来,current_thread::Runtime 也进行了一些增量改进。

@sdroege 添加了一个 Handle,允许从其他线程将任务 spawn 到 runtime 上 (#340)。这是通过使用 channel 将任务发送到 runtime 线程来实现的(与 tokio-core 使用的策略类似)。

并且 @jonhoo 实现了 block_on_all 函数 (#477) 并修复了一个关于跟踪活动 futures 数量和协调 shutdown 的 bug ([#478])

定时器改进

tokio::timer 确实获得了一个新功能:DelayQueue。这种类型允许用户存储值,这些值在一段时间后会被返回。这对于支持更复杂的时间相关情况非常有用。

让我们以 cache 为例。cache 的目标是为与 key 关联的值保留一段时间。时间过后,该值将被删除。一直以来都可以使用 tokio::timer::Delay 来实现这一点,但这有点挑战性。当 cache 有很多条目时,必须扫描所有条目以检查它们是否需要被删除。

使用 DelayQueue,实现变得更加高效

#[macro_use]
extern crate futures;
extern crate tokio;
use tokio::timer::{delay_queue, DelayQueue, Error};
use futures::{Async, Poll, Stream};
use std::collections::HashMap;
use std::time::Duration;

struct Cache {
    entries: HashMap<CacheKey, (Value, delay_queue::Key)>,
    expirations: DelayQueue<CacheKey>,
}

const TTL_SECS: u64 = 30;

impl Cache {
    fn insert(&mut self, key: CacheKey, value: Value) {
        let delay = self.expirations
            .insert(key.clone(), Duration::from_secs(TTL_SECS));

        self.entries.insert(key, (value, delay));
    }

    fn get(&self, key: &CacheKey) -> Option<&Value> {
        self.entries.get(key)
            .map(|&(ref v, _)| v)
    }

    fn remove(&mut self, key: &CacheKey) {
        if let Some((_, cache_key)) = self.entries.remove(key) {
            self.expirations.remove(&cache_key);
        }
    }

    fn poll_purge(&mut self) -> Poll<(), Error> {
        while let Some(entry) = try_ready!(self.expirations.poll()) {
            self.entries.remove(entry.get_ref());
        }

        Ok(Async::Ready(()))
    }
}

许多其他小的改进

除了上面列出的内容之外,Tokio 在大多数 crates 中还获得了许多小的改进和错误修复。这些都是由我们出色的社区提供的。我希望随着时间的推移,越来越多的人将加入构建 Tokio 的行列,并帮助它继续发展。

因此,非常感谢迄今为止所有为 Tokio 做出贡献的人