【译】Async/Await(五)—— Executors and Wakers
原文标题:Async/Await
原文链接:https://os.phil-opp.com/async-await/#multitasking
公众号: Rust 碎碎念
翻译 by: Praying
Executors and Wakers
使用 async/await,可以让我们以一种全完异步的方式来与 future 进行更为自然地协作。然而,正如我们之前所了解到的,future 在被轮询之前什么事也不会做。这意味着我们必须在某个时间点上调用poll
,否则异步的代码永远都不会执行。
对于单个的 future,我们总是通过使用一个循环手动地等待每个 future。但这种方式十分地低效,且对于一个创建大量 future 的程序来讲也不适用。针对这个问题的最常见的解决方式是定义一个全局的executor
Executors(执行器)
executor 的作用在于能够产生 future 作为独立的任务,通常是通过某种spawn
方法。接着 executor 负责轮询所有的 future 直到它们完成。集中管理所有的 future 的巨大优势在于,只要当一个 future 返回Poll::Pending
时,executor 就可以切换到另一个 future。因此,异步操作可以并行执行并且 CPU 始终保存繁忙。
许多 executor 的实现充分利用 CPU 多核心的优势,它们创建了一个线程池[1],该线程池能够在工作足够多的情况下充分利用所有的核心,并且使用类似work stealing[2]的方式在核心之间进行负载均衡。还有针对嵌入式系统优化了低延迟和内存负载的特殊的 executor 实现。
为了避免重复轮询 future 的负担,executor 通常会充分利用由 Rust 的 future 支持的 waker API。
Waker
Waker API 背后的设计理念是,一个特定的Waker[3]类型,包装在Context
类型中,被传递到poll
的每一次执行。这个Waker类型
由 executor 创建,并且可以被异步任务用来通知自己的完成。因此,executor 不需要在一个 future 返回Poll::Pending
之前对其调用poll
,直到它被对应的 waker 调用。
这可以通过一个小例子来阐述:
async fn write_file() {
async_write_file("foo.txt", "Hello").await;
}
这个函数异步地把一个字符串“Hello”写入到文件foo.txt
中。因为硬盘写入需要一点儿时间,所以 future 上的第一次poll
调用很大可能返回Poll::Pending
。尽管如此,硬盘驱动将把传递给poll
调用的Waker
存储起来,并在当文件被完全写入磁盘后使用它来提醒 executor,通过这种方式,executor 在收到 waker 提醒之前不需要浪费时间一次又一次地去轮询这个 future。
当我们在后面的章节实现自己的支持 waker 的 executor 时,我们就会看到Waker
类型更详细的工作原理。
协作式多任务?
在本文(系列)开头,我们讨论了抢占式和协作式多任务。抢占式多任务依赖于操作系统在运行中的任务间进行强制切换,协作式多任务则需要任务通过一个yield
操作自愿放弃对 CPU 的控制权。协作式多任务的巨大优势在于,任务可以自己保存自身状态,从而产生更为高效的上下文切换,并使得在任务间共享相同的调用栈成为可能。
虽然看上去可能不太明显,但是 future 和 async/await 是一种协作式多任务模式的实现:
每个被添加到 executor 的 future 是一个协作式任务。
不同于显式的
yield
操作,future 通过返回Poll::Pending
(或者是结束时的Poll::Ready
)来放弃对 CPU 核心的控制权。没有什么可以强制让 future 放弃 CPU,future 可以永远不从
poll
里面返回,例如,无限循环。因为每个 future 都能阻塞 executor 中其他 future 的执行,所以我们需要确信它们不是恶意的。
Futures 内部存储了需要在下次
poll
调用继续执行所需的所有状态。通过 async/await,编译器会自动探测所有需要的变量并将其存储在生成的状态机内部。只保存继续执行需要的最小状态 因为 poll
方法在返回时放弃了调用栈,所以同一个栈可以被用于轮询其他的 future。
我们可以看到,future 和 async/await 完美契合协作式多任务模式,它们只是用了一些不同的技术。接下来,我们将会交替使用“任务(task)”和“future”。
参考资料
线程池: https://en.wikipedia.org/wiki/Thread_pool
[2]
work stealing: https://en.wikipedia.org/wiki/Work_stealing
[3]
Waker: https://doc.rust-lang.org/nightly/core/task/struct.Waker.html
```
【译】Async/Await(五)—— Executors and Wakers的更多相关文章
- [译]async/await中使用阻塞式代码导致死锁 百万数据排序:优化的选择排序(堆排序)
[译]async/await中使用阻塞式代码导致死锁 这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的 ...
- [译]async/await中使用阻塞式代码导致死锁
原文:[译]async/await中使用阻塞式代码导致死锁 这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Clea ...
- [译]async/await中阻塞死锁
这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...
- [译]Async/Await - Best Practices in Asynchronous Programming
原文 避免async void async void异步方法只有一个目的:使得event handler异步可行,也就是说async void只能用于event handler. async void ...
- 【译】异步JavaScript的演变史:从回调到Promises再到Async/Await
我最喜欢的网站之一是BerkshireHathaway.com--它简单,有效,并且自1997年推出以来一直正常运行.更值得注意的是,在过去的20年中,这个网站很有可能从未出现过错误.为什么?因为它都 ...
- 聊聊多线程那一些事儿 之 五 async.await深度剖析
hello task,咱们又见面啦!!是不是觉得很熟读的开场白,哈哈你哟这感觉那就对了,说明你已经阅读过了我总结的前面4篇关于task的文章,谢谢支持!感觉不熟悉的也没有关系,在文章末尾我会列出前四 ...
- 【译】Async/Await(一)——多任务
原文标题:Async/Await 原文链接:https://os.phil-opp.com/async-await/#multitasking 公众号: Rust 碎碎念 翻译 by: Praying ...
- 【译】Async/Await(二)——Futures
原文标题:Async/Await 原文链接:https://os.phil-opp.com/async-await/#multitasking 公众号: Rust 碎碎念 翻译 by: Praying ...
- 【译】Async/Await(三)——Aysnc/Await模式
原文标题:Async/Await 原文链接:https://os.phil-opp.com/async-await/#multitasking 公众号: Rust 碎碎念 翻译 by: Praying ...
随机推荐
- 【Linux】配置ssh留下的一些思考和大坑解决办法
今天传包突然有问题,结果发现是ssh出现了问题,密钥也在里面,都是正常的,但是还有什么问题呢? 后来总结下需要注意点: 1.最开始你要检查.ssh/ 这个文件夹的权限,看下权限是否为700或者为75 ...
- Empire
Empire 内网渗透神器 一 基本渗透 安装 git clone https://github.com/BC-SECURITY/Empire/ ./setup/install.sh 启动 ./emp ...
- D2Admin 登录用户重新初始话右侧菜单
背景 最近用到D2Admin开发项目,用户登录菜单要根据用户角色权限获取,但是又不想用官网的方案(vue基于d2-admin的RBAC权限管理解决方案),所以自己加了个只修改 menuAside的方案 ...
- Django-http协议
Http协议:超文本传输协议(应用层程序).它是客户端和服务端请求和应答的标准.Http的请求响应模型:1.客户端连接到web服务器一个http客户端,与web服务器的http端口(默认是80)建立了 ...
- Python干货:了解元组与列表的使用和区别
元组是 Python 对象的集合,跟列表十分相似.下面进行简单的对比. 列表与元组 1.python中的列表list是变量,而元组tuple是常量. 列表:是使用方括号[],元组:则是使用圆括号() ...
- 07. struts2中对Action的管理方式
web.xml配置文件的常用代码 <filter> <filter-name>struts2</filter-name> <filter-class>o ...
- b站视频_下载_去水印_视频转mp4-批量下载神器
b站下载_视频_去水印_转mp4_批量下载的解决办法 以下问题均可解决 b站下载的视频如何保存到本地 b站下载的视频在那个文件夹里 b站下载视频转mp4 b站下载app b站下载在哪 b站下载视频电脑 ...
- ubuntu中如何安装selenium+chrome(headless)无界面浏览器?
selenium是一个Web的自动化测试工具,它可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生.但是它自身不带浏览器,不支持浏览器的功能,因此它 ...
- SpringBoot-Maven打包压缩瘦身
SpringBoot-Maven打包压缩瘦身 一.Spring Boot 可执行 jar 分析 1.1 打包 1.2 两种 jar 的比较 1.3 一次打包两个 jar 二.SpringBoot迭代发 ...
- Docker安装Mycat并实现mysql读写分离,分库分表
Docker安装Mycat并实现mysql读写分离,分库分表 一.拉取mycat镜像 二.准备挂载的配置文件 2.1 创建文件夹并添加配置文件 2.1.1 server.xml 2.1.2 serve ...