主要观点:
- 性能不止一种,21 世纪应关注延迟(latency)而非吞吐量(throughput)。
- 非阻塞代码很重要,有多种方式实现,如使
fibonacci
函数非阻塞。 - 介绍了非阻塞相关概念:非阻塞(代码从不阻塞关键线程)、异步(结构上呈现执行间的显式依赖)、并发(可调度独立任务运行)、并行(两个任务可在同一物理瞬间运行),且它们易混淆。
- 讨论了线程的优缺点:能实现并发和并行,但难用、消耗资源、可能被 GIL 限制、上下文切换有成本。
- 进程也有优缺点:不受 GIL 限制可并行运行,垃圾回收独立,但开销大、通信成本高、运行慢。
- 介绍了通过手动控制并发来解决问题的方式,如将
fibonacci
函数重写成并发代码,还介绍了延续传递风格(CPS)、生成器/迭代器等方式来实现异步和非阻塞代码。 async/await
是使代码异步的语法糖,在 Python、Rust、JavaScript 中都有应用,但有一些缺点,如堆栈问题、性能成本、开发者理解困难等,且async/await
本身不能使代码 magically non-blocking。- 异步和非阻塞 I/O:操作系统或底层库可能提供非阻塞调用,否则需用线程。
- Go 语言有独特的 M:N 调度器,能轻松实现并发,资源使用和认知负载低,但代码难推理,有一些问题。
- 其他有 M:N 调度的语言如 Erlang、Haskell、Rust、Java、OCaml 等,Rust 移除该特性有其原因。
- OCaml 有独特的并发机制,通过效果(effect)实现上下文可定制的重试等,性能和栈管理较复杂。
关键信息:
- 不同语言中实现异步和非阻塞的方式及优缺点。
- 各种编程概念的定义和区别。
- 线程、进程、异步等在性能和编程中的作用。
重要细节:
- Python 中线程创建和启动每个约 6µs,进程运行自己的 Python 副本等。
- JavaScript 有双事件循环,
Promise.then()
在微 ticks 执行。 - Rust 中
async/await
编译为类似生成器的有限状态机,支持取消 futures 等。 - Go 中启动 goroutine 动态分配新栈,调度器可停止和恢复 goroutine 等。
- OCaml 中通过
Fiber.yield()
实现协作式上下文切换,效果(effect)机制等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。