Hacker News 中文摘要

RSS订阅

SBCL纤程——轻量级协作线程 -- SBCL Fibers – Lightweight Cooperative Threads

文章摘要

这篇文章介绍了SBCL Fibers,一种轻量级用户态协作线程的实现方案。文章描述了其设计目标、编程API以及当前开发进展,该项目仍在积极开发中,代码可在GitHub的fibers-v2分支上试用。

文章总结

SBCL Fibers:轻量级协作式线程

本文介绍了SBCL(Steel Bank Common Lisp)中轻量级用户态协作式线程(Fibers)的实现方案,该实现正在积极开发中,细节可能发生变化。

1. 引言

1.1 动机:为什么需要Fibers?

许多服务器工作负载是并发而非并行的。一个处理10,000个连接的Web服务器大部分时间都在等待网络I/O,每个请求的实际计算量很小。自然的编程模型是为每个连接分配一个控制线程,但OS线程在这种规模下开销过大。

Fibers提供了第三种选择:Fibers是拥有独立控制栈和绑定栈的用户空间线程,由库级调度器而非内核调度。Fibers保持了顺序编程模型,同时实现了事件驱动I/O的资源效率。

1.2 设计目标

实现遵循以下优先级: 1. GC下的正确性 2. 透明集成 3. 低切换开销 4. 支持大量纤程 5. 多核利用

1. 3 术语

  • Fiber:轻量级协作线程
  • Carrier thread:运行Fibers的OS线程
  • Scheduler:每个carrier的管理结构
  • Yield:Fiber主动暂停自己
  • Resume:调度器恢复Fiber执行

2. 编程API

2.1 创建和运行Fibers

使用make-fiber创建Fiber: lisp (make-fiber function &key name stack-size binding-stack-size initial-bindings)

2.2 让出和等待

fiber-yield暂停当前Fiber: lisp (fiber-yield &optional wake-condition)

2.3 Fiber休眠和定时等待

fiber-sleep暂停当前Fiber指定时间: lisp (fiber-sleep seconds)

2.4 Fiber暂停(基于条件的暂停/恢复)

fiber-park是通用暂停原语: lisp (fiber-park predicate &key timeout)

2.5 Fiber连接

fiber-join等待目标Fiber完成: lisp (fiber-join target &key timeout)

3. 架构概述

3.1 Carrier线程和调度器

运行时围绕两级层次结构组织: - Carrier线程是普通SBCL OS线程 - 每个调度器组包含多个调度器

3.2 Fiber生命周期状态机

Fiber经历五个状态: :created → :runnable → :running ↑ | | yield/wake +── :suspended | v :dead

4. 上下文切换

4.1 寄存器保存/恢复约定

仅保存平台ABI定义的被调用者保存寄存器。

4.2 fiber_switch汇编例程

上下文切换的核心,作为Lisp汇编例程实现。

5. 栈管理

5.1 控制栈布局和保护页

每个Fiber的控制栈是连续区域,底部有保护页。

5.2 绑定栈(独立分配)

每个Fiber有独立的绑定栈用于动态变量绑定。

6. 动态变量绑定(TLS)

6.1 问题:unbind_to_here清零条目

解决方案是使用TLS覆盖方法。

7. 垃圾收集器集成

7.1 双列表设计

  • all_fiber_gc_info:已创建但未销毁的Fiber列表
  • all_active_fiber_contexts:当前运行调度器的carrier列表

8. 调度器设计

8.1 调度器循环

核心结构: fallback init-carrier-fiber-context() loop { fiber = fast-path-pop() or (maintenance + pop-or-steal) ... }

9. 工作窃取

9.1 Chase-Lev无锁双端队列

每个调度器的运行队列是Chase-Lev工作窃取队列。

10. I/O多路复用

10.1 平台抽象

使用平台特定的I/O多路复用: - Linux:epoll - BSD/macOS:kqueue - 回退:批量poll()

11. 截止时间调度

11.1 带内联索引的二叉最小堆

调度器维护按fiber-deadline排序的二叉最小堆。

12. Fiber终止和清理

12.1 Lisp跳板(fiber-trampoline

当Fiber首次启动时的入口路径。

13. 与SBCL的集成

13.1 线程结构扩展

SBCL线程结构扩展了三个Fiber相关槽。

14. 性能

14.1 HTTP基准测试

在10,000连接时,Fibers保持102,710 r/s,而线程降至55,493 r/s。

15. 平台支持

支持x86-64、ARM64、ARM32、PPC64、PPC32和RISC-V平台。

附录A:在Hunchentoot中使用Fibers

Hunchentoot的标准任务管理器创建OS线程,而Fiber任务管理器用Fibers替换这些线程。

A.1 Fiber任务管理器

lisp (defclass fiber-taskmaster (hunchentoot:taskmaster) ((group :accessor fiber-taskmaster-group :initform nil) (carrier-count :initarg :carrier-count :initform nil :accessor fiber-taskmaster-carrier-count)))

A.2 任务管理器方法

包括execute-acceptorhandle-incoming-connectionshutdown方法。

A.3 启动服务器

示例展示了如何用Fiber任务管理器启动Hunchentoot服务器。

A.4 工作原理

详细说明了Fiber任务管理器的工作流程。

A.5 SSL

讨论了使用SSL时的注意事项和纯TLS实现的优势。

A.6 注意事项

包括会话锁定、超时、日志记录和最大连接数限制等考虑因素。

评论总结

以下是评论内容的总结:

  1. 关于命名争议

    • 有用户调侃应命名为"Anthony Green Threads"(评论1:"They should be called Anthony Green Threads")
    • 另一用户偏好"fiber"而非"green threads",但承认后者更常见(评论2:"I personally like the name fiber better than green threads")
  2. 技术文档需求

    • 用户询问内存区域(memory arena)功能的相关文档(评论3:"Is there a similar document for the memory arena feature?")
  3. 关于SBCL的讨论

    • 有用户简单提及SBCL(Steel Bank Common Lisp)(评论4:"SBCL - Steel Bank Common Lisp")
    • 另一用户建议查看邮件列表以获取背景信息(评论5:"I strongly recommend having a look at the mailing list")
  4. 关于LLM能力的质疑

    • 用户质疑LLM平衡括号的能力(评论6:"I thought LLMs were bad at balancing parentheses?")
  5. Actor模型与性能讨论

    • 用户批评Fiber的256KB栈开销过大,推崇Actor模型(评论7:"256Kb stack per Fiber is still insane overhead compared to Actors")
    • 指出多数开发者不了解Actor模型的性能优势(评论7:"less than 2% of devs even know what the Actor model is")
  6. 标题误解

    • 用户误以为这是材料科学论文(评论8:"I really thought this was gonna be a sick material science paper")