Tokio 新版本发布,现在支持文件系统
2018年5月5日
比我最初希望的要花更长的时间(总是这样),但 Tokio 的新版本已经发布了。此版本除了其他功能外,还包括一组新的 API,允许从异步上下文中执行文件系统操作。
文件系统 API
与文件(和其他文件系统类型)交互需要*阻塞系统调用,我们都知道阻塞和异步不能混合使用。因此,从历史上看,当人们问“如何从文件中读取和写入文件?”时,答案是使用线程池。 想法是,当必须执行阻塞读取或写入时,它在线程池上完成,这样它就不会阻塞异步 reactor。
需要单独的线程池来执行文件操作需要消息传递。 异步任务必须向线程池发送消息,要求它从文件中读取,线程池执行读取并将结果填充到缓冲区中。 然后,线程池将缓冲区发送回异步任务。 这不仅增加了调度消息的开销,而且还需要分配缓冲区来来回发送数据。
现在,借助 Tokio 新的 文件系统 API,不再需要这种消息传递开销。 添加了一个新的 File
类型。 此类型看起来与 std
提供的类型非常相似,但它实现了 AsyncRead
和 AsyncWrite
,使其可以安全地直接从 Tokio 运行时上运行的异步任务中使用。
由于 File
类型实现了 AsyncRead
和 AsyncWrite
,因此它可以像从 Tokio 使用 TCP 套接字一样使用。
截至今天,文件系统 API 非常精简。 还有许多其他 API 需要实现,以使 Tokio 文件系统 API 与 std
保持一致,但这些都留给读者作为练习提交 PR!
* 是的,有些操作系统提供完全异步的文件系统 API,但这些 API 要么不完整,要么不可移植。
标准输入和输出
此版本的 Tokio 还包括异步 标准输入 和 标准输出 API。 因为很难以可移植的方式提供真正的异步标准输入和输出,所以 Tokio 版本使用了与阻塞文件操作 API 类似的策略。
阻塞
这些新 API 的实现归功于新的 blocking
API,它允许注释将阻塞当前线程的代码段。 这些阻塞部分可以包括阻塞系统调用、等待互斥锁或 CPU 密集型计算。
通过告知 Tokio 运行时当前线程将阻塞,运行时能够将事件循环从当前线程移动到另一个线程,从而释放当前线程以允许阻塞。
这与使用消息传递在线程池上运行阻塞操作相反。 不是将阻塞操作移动到另一个线程,而是移动整个事件循环。
实际上,将事件循环移动到另一个线程比移动阻塞操作便宜得多。 这样做只需要几个原子操作。 Tokio 运行时还保留一个备用线程池,以便尽可能快地移动事件循环。
这也意味着使用 blocking
注解和 tokio-fs
必须从 Tokio 运行时的上下文中完成,而不是从其他 futures 感知的执行器中完成。
当前线程运行时
此版本还包括运行时的“当前线程”版本(感谢 kpp)。 这与现有运行时类似,但所有组件都在当前线程上运行。 这允许运行未实现 Send
的 futures。