2024-08-22

35 篇热帖

4. Celebrating 6 years since Valve announced Steam Play Proton for Linux (www.gamingonlinux.com)

Proton 宣布六周年:革新 Linux 游戏生态

Valve 于六年前宣布 Steam Play Proton,彻底改变了 Linux 游戏格局,推动 Steam Deck 和桌面 Linux 游戏的繁荣发展。没有 Proton,Steam Deck 无法实现,因为它依赖于 Proton 来运行海量游戏,避免了在 Linux 掌机上缺乏主流游戏的困境。

Proton 基于 Wine 开发,由 Valve 开发者、承包商及 Wine 社区共同贡献。六年来,已发布 66 个版本,包含 388 项更改,体现了持续的开发和优化工作,确保玩家在 Steam 上点击即可运行游戏。

当前,Linux 游戏兼容性大幅提升。根据 ProtonDB 社区数据,有 22,002 款游戏被至少一人报告可运行,13,297 款被至少两人报告,9,751 款有三人以上报告。Valve 的 Steam Deck 验证系统则将 5,297 款游戏评为“已验证”,10,646 款评为“可玩”。尽管 Steam 拥有超过 100,000 款游戏,但许多未报告的游戏也可能通过 Proton 直接运行。

如今,玩家可以轻松运行《地狱潜者 2》、《博德之门 3》、《黑神话:悟空》等热门游戏。然而,反作弊支持仍是主要挑战,需要更多开发者启用已支持的反作弊系统。Proton 的六年历程证明了其在推动 Linux 游戏生态中的关键作用。

5. I sped up serde_json strings by 20% (purplesyringa.moe)

serde_json字符串解析性能优化20%的实践

背景

serde_json是Rust生态中广泛使用的JSON序列化/反序列化库,拥有超过26000个依赖项。作者通过性能分析发现其错误路径比成功路径慢2倍以上,主要瓶颈在于position_of_index函数,该函数通过逐字符遍历将字符串索引转换为行列号,性能低下。

关键优化措施

1. 错误路径优化

原实现使用简单循环统计换行符和计算列号。改用memchr库的SIMD优化函数:

  • 使用memrchr查找最后一个换行符
  • 使用memchr_iter计数换行符数量
  • 错误路径速度提升约50%,与成功路径差距从60%缩小到15%

2. 字符串转义检测优化

原代码使用查找表ESCAPE逐字节检查转义字符。尝试多种方案:

  • 两遍扫描失败:先找\",再检查控制字符,因内存带宽增加反而更慢
  • SWAR(寄存器内SIMD)技术
    • 使用64位寄存器模拟SIMD操作
    • 通过位运算同时检测\"和控制字符(ASCII < 0x20)
    • 核心公式:!c & (c - 0x2020...) & 0x8080...检测控制字符
    • 针对短字符串优化:先检查首字符再进入SWAR循环
  • 整体提升:在部分数据集上获得5%-23%加速

3. Unicode十六进制解析优化

原实现使用256字节查找表,逐字符解析。改进方案:

  • 使用32位整型存储查找表,消除每次迭代的分支判断
  • 引入预计算的移位表HEX0/HEX1,将两次移位合并为一次
  • 使用符号扩展指令(movsx)和单指令分支判断
  • 俄罗斯语文本测试中速度提升21%(284MB/s → 344MB/s)

4. UTF-8编码优化

原实现调用标准库encode_utf8,导致不必要的memset/memcpy调用:

  • 手动实现UTF-8编码逻辑
  • 避免临时缓冲区的零初始化和内存拷贝
  • 进一步提升9%性能(344MB/s → 374MB/s)

优化效果汇总

测试数据集 优化前(MB/s) 优化后(MB/s) 提升幅度
canada 283 291-292 ~3%
citm_catalog DOM 1642 1636-1736 -1%~+6%
twitter 986 905-790 -8%~+10%
俄罗斯语文学 284 374 32%

技术启示

  1. 算法选择比微优化更重要:SWAR技术在避免平台特定代码的同时接近原生SIMD性能
  2. 避免两遍扫描:在内存受限场景中,单遍算法通常优于看似优化的两遍算法
  3. 理解编译器行为:标准库函数可能产生意外的底层调用,手动实现有时更高效
  4. 权衡取舍:短字符串的微小性能回退可接受,以换取长字符串的显著提升

这些优化已作为PR提交给serde_json项目并被合并,将惠及整个Rust生态。

6. Continuous reinvention: A brief history of block storage at AWS (www.allthingsdistributed.com)

AWS弹性块存储(EBS)发展历程:持续创新之路

核心摘要

本文由AWS资深工程师Marc Olson撰写,回顾了Elastic Block Store(EBS)从2008年诞生至2024年间的演进历程。EBS从一个简单的、依赖共享硬盘驱动器(HDD)的网络附加块存储服务,发展成为能够每天处理超过140万亿次操作的庞大分布式网络存储系统。其发展过程并非一蹴而就,而是通过持续的增量式改进、挑战假设和跨栈协作完成的。

关键技术挑战与解决方案

  1. 早期阶段(HDD时代)与“嘈杂邻居”问题

    • 初始设计基于HDD,其机械特性导致IOPS(每秒输入输出操作)性能有限(约120-150次/秒),且尾部延迟高。
    • 核心挑战是性能隔离:不同客户的工作负载相互干扰,即“嘈杂邻居”问题,严重影响了用户体验和业务可靠性。
    • 初步解决方案包括优化调度算法和将工作负载分散到更多磁盘,但效果有限。
  2. 向SSD转型与性能突破

    • 2012年左右,EBS开始采用固态硬盘(SSD),解决了HDD的机械延迟问题。
    • 引入了Provisioned IOPS卷类型,性能提升至最高1000 IOPS,平均延迟降至2-3毫秒。
    • 然而,单纯替换硬件并未完全解决问题。性能瓶颈转移至网络和软件栈,团队意识到需要全面的系统性优化。
  3. 系统性优化与硬件创新

    • 全面可观测性:建立了贯穿所有子系统的端到端IO追踪和金丝雀测试,以精准识别瓶颈。
    • 减少队列与优化虚拟化
      • 发现并优化了EC2主机(Xen hypervisor)中的默认队列设置,其初始值远不能满足大规模IO需求。
      • 通过Nitro硬件卸载,将网络(VPC)和存储IO处理从通用hypervisor转移到专用硬件,消除了多个操作系统队列,显著降低了延迟并提升了安全性。
    • 自研网络协议:针对传统TCP协议的局限,开发了可扩展可靠数据报(SRD) 协议。该协议专为AWS数据中心网络设计,支持多路径传输和乱序执行,提高了网络利用率和故障恢复能力。
    • 底层硬件定制:最终,团队甚至开始为EBS设计定制化的SSD,以完全匹配其工作负载需求。
  4. 约束驱动的创新

    • 在资源受限的情况下(如无法大规模更换旧服务器),团队创造性地在旧服务器的机箱空隙中手动添加SSD,作为写入缓冲层,以渐进方式将SSD的优势扩展至所有卷类型。
    • 系统设计之初就支持非破坏性维护,允许在不影响客户工作负载的情况下迁移卷、更新软件和更换硬件,这是长期演进的基础。

工程原则与组织文化

  1. 渐进式迭代:坚持“分而治之”和增量交付的策略。设定长期目标,但通过一系列小的、可验证的步骤来推进,从而快速交付价值并灵活调整方向。
  2. 跨栈协作:性能问题跨越硬件、固件、网络、操作系统和应用多个层次。因此,建立了跨团队协作机制(如跨AWS的网络性能专家组),将不同领域的专家聚集起来共同解决问题。
  3. 赋能与信任:作者反思了个人角色从“深度问题解决者”到“赋能型领导者”的转变。通过如同行调试等方法,鼓励团队集体智慧,移除障碍但保留安全护栏,从而释放了组织更大的创造力。
  4. 始终质疑假设:无论是硬件限制、软件默认设置,还是网络协议,团队始终保持批判性思维,不断挑战现状,这驱动了每一层的改进。

结论

EBS的演变史展示了一个云基础服务如何通过持续关注客户体验(性能、可用性、隔离性),结合硬件创新、软件优化和组织进化,实现了从毫秒级延迟到亚毫秒级延迟、从数百IOPS到单实例数十万IOPS的跨越。其核心启示在于:在超大规模系统中,约束催生创新,而成功的路径往往在于对复杂问题的持续分解、测量和增量优化。

7. Show HN: A Ghidra extension for exporting parts of a program as object files (github.com)

Ghidra 对象文件导出扩展插件

项目概述

该 Ghidra 扩展插件允许用户将程序的部分内容导出为包含有效元数据(如符号和重定位表)的对象文件(Object files)。导出的文件可直接被工具链复用,从而实现程序的“反链接(delinking)”。

核心应用场景

  • 高级二进制补丁:利用链接器自动缝合原始与修改部分,替代手工拼接。
  • 软件移植:隔离系统无关代码并替换系统相关部分。
  • 格式转换:在不同的程序或对象文件格式之间进行转换。
  • 创建代码库:提取程序片段以便在其他项目中复用。
  • 反编译项目:将程序拆分为多个对象文件,并以“忒修斯之船”的方式逐步重写。

支持的架构与文件格式

  • x86:支持 COFF、ELF、OMF。
  • x86_64:支持 COFF、ELF。
  • MIPS:仅支持 ELF。

工作原理

对象文件由可重定位段字节、符号表和重定位表组成。链接器在生成可执行文件后,通常会丢弃重定位表(有时也包括符号表)。该插件通过深入分析重建这些丢失的数据,从而将程序逆向还原为对象文件。

构建、安装与使用

构建与安装

  • 构建:设置 GHIDRA_INSTALL_DIR 环境变量,使用 Gradle 构建。需配置 GitHub Token 解决 Maven 仓库认证问题,或通过子模块安装独立依赖。
  • 安装:在 Ghidra 中安装扩展包,并在 CodeBrowser 的实验性功能中启用 RelocationTableSynthesizedPlugin 插件。

使用流程

  1. 在 Listing 视图中选中需要提取的地址集合。
  2. 运行“重定位表合成分析器(Relocation table synthesizer analyzer)”。
  3. 通过 File > Export Program 调用导出功能生成可重定位对象文件。

关键注意事项

  • 无需全局逆向:无需提前逆向整个程序。导出成功率主要取决于所选子集及其外部引用的元数据准确性(如函数/指针位置、符号目标及两者间的引用)。
  • 高度依赖数据库:分析器依赖 Ghidra 数据库的准确性,错误或缺失的信息会导致重定位失败或遗漏。
  • 保持数据同步:对象文件导出器依赖分析器的结果,导出前务必运行分析器以确保重定位表为最新状态。
10. No "Hello", No "Quick Call", and No Meetings Without an Agenda (switowski.com)

文章总结:远程工作三大沟通禁忌与改进方法

本文指出了远程工作中三种常见的低效沟通方式:以“你好”开头的模糊消息、未说明缘由的“快速通话”请求,以及缺乏议程的会议邀请。作者认为这些方式浪费时间、降低效率,并详细阐述了其弊端及改进方案。

1. 禁忌一:以“你好”开头的模糊消息

  • 问题:仅发送“你好”或类似问候,然后等待回复才说明问题,会造成不必要的延迟,且使对方无法判断问题的紧急性与性质。
  • 改进:直接提问,提供完整上下文。作者以技术问题为例,展示了从最差到最佳的提问方式:
    • 最差:“你好,我有个问题。”
    • 较好:“你好,frobnicate函数不工作。”
    • 很好:“你好,我在feature-123分支上,在预发布环境运行frobnicate函数时,报错Error: missing argument 'count'。”
    • 最佳实践:包含完整错误信息(或堆栈跟踪)、具体环境、分支,以及已尝试的排查步骤(如与生产环境对比、拉取最新代码等)。这能让帮助者快速理解问题,避免误解,并提高获得有效帮助的效率。

2. 禁忌二:未说明缘由的“快速通话”请求

  • 问题
    • 比文字消息更分散注意力,中断深度工作,恢复成本高。
    • 很多问题通过几条文字消息即可解决,通话并非必要。
    • 在文字描述问题的过程中(类似“橡皮鸭调试”),提问者自己可能就找到了解决方案。
    • 通话内容转瞬即逝,不利于未来回溯;文字记录则可长期保存。
  • 改进:当对方反问“什么问题?”时,应预先用文字清晰描述问题。这既是对对方工作的尊重,也有利于问题解决和知识沉淀。

3. 禁忌三:没有议程的会议

  • 问题:参与者对会议目的一无所知,导致无法准备,会议效率低下,可能浪费多人时间。
  • 改进:遵守“无议程,不参加”的原则。会议组织者必须提前发送清晰的议程或详细描述。其好处包括:
    • 参与者可提前准备,甚至提前通过文档或信息自行解决问题,从而取消不必要的会议
    • 会议有明确目标和检查清单,便于跟踪进度和判断是否达成目的。
    • 参与者能判断自己是否必需出席,以便合理安排时间。
  • 针对技术会议的建议:邀请技术人员时,若目的是:
    1. 了解新事物:可先提供相关文档,会议可能变得多余或更高效。
    2. 提问具体技术问题文字提问更佳,能让回答者深思熟虑,避免现场仓促回答。
    3. 询问过往工作:提前告知议题,让对方有时间回顾,避免会议中因遗忘细节而尴尬和低效。

核心原则:上下文为王

远程协作中,提供充足、清晰的上下文是高效沟通的关键。这需要提问者在寻求帮助时:

  1. 尽可能详细地描述问题。
  2. 尝试用文字形式阐明问题再考虑通话。
  3. 组织会议时,为参与者准备清晰的议程。

遵循这些原则,不仅能更快解决问题,也能让同事更乐于提供帮助,提升整体远程协作效率。

11. Accident Forgiveness (fly.io)

事故宽恕:公共云账单的意外费用处理方案

公共云账单令人恐惧。其弹性资源定价模式与传统托管不同,用户可能因代码错误、配置失误或资源泄漏产生巨额意外费用,且潜在支出几乎无上限。

隐含的事故宽恕

大多数云提供商虽未明示,但设有账单支持团队处理争议账单。用户若因失误产生高额费用,通常可获得减免。这虽提供一定保障,但流程依赖人工沟通(邮件/电话),速度慢且结果不确定。

明确的事故宽恕政策

Fly.io 推出明确政策:凡签订支持合同的客户,意外产生的费用将获退款,几乎无需解释。此政策旨在降低用户心理负担,鼓励创新尝试,无需财务部门严格监管。

实施挑战与限制

  • 欺诈风险:完全自动化的宽恕可能被滥用(如加密货币挖矿),因此采用渐进式推出。
  • 计费系统限制:旧系统难以支持有意义的账单警报;新系统开发历时较长,目前仍在迁移中。
  • 明确例外:若用户故意利用政策(如恶意刷单),保留终止服务权利。

事故保护:未来方向

当前退款政策仅为第一步。Fly.io 正构建新计费系统,以实现:

  1. 主动预警:检测异常账单波动,在计费前标记可疑部署。
  2. 预留定价优化:自动识别用户资源使用模式,提供回溯性预留折扣,降低长期成本。
  3. 根本避免费用:通过系统改进,从源头上减少意外费用产生。

此策略基于公共云基础设施的剩余容量特性——意外资源消耗实际边际成本低,因此宽恕政策对提供商与用户均有益。长期来看,该政策将持续优化直至条件变化。

12. Designing my own watch (2020) (willem.com)

作者决定定制一款完全符合个人偏好的手表。在梳理需求后,他确立了以下核心标准:指针显示、设计简洁、自动上弦(无需手动)、防水、具备夜视功能、风格经典、外观低调、材质本色不加掩饰。

他发现了瑞士小型制表公司ochs und junior,其创始人兼设计师路德维希·厄克林以通过极简的机械结构实现复杂功能而闻名,致力于减少零件数量以提升可靠性。这一理念与作者追求简洁的价值观高度契合。

经过沟通,作者定制了一款年历腕表。其主要特性包括:

  • 材质与结构:表壳由钛金属制成,直径36毫米,通过精铣去除多余材料以减轻重量。防水设计,配备旋入式表冠。
  • 复杂功能:年历功能(每月仅需在二月末手动调校一次)仅通过3个额外零件实现,体现了公司简化机械的哲学。
  • 读时与显示:时、分、秒针均涂有SuperLuminova夜光材料,确保黑暗中清晰可读。表盘设计低调,日间不易引人注目。
  • 表带与佩戴:配备两种表带:一条天然防水的鳄鱼皮表带,一条带凯夫拉核心的黑色织物表带(适合骑行)。表扣同样为精铣钛金属,轻量化设计。弧形表壳确保了佩戴舒适性。

整个定制过程历时数月,作者与制表师保持沟通并收到进度图片。最终收到的手表符合所有预期,作者对其简约、精准和独特的个性化设计深感满意。文章总结认为,在快速消费的时代,拥有一件根据个人需求精心打造的、经久耐用的物品,是很有意义的。

13. Show HN: Isaiah – open-source and self-hosted app to manage everything Docker (github.com)

Isaiah:开源自托管Docker管理应用摘要

简介

Isaiah是一个开源、可自托管的Web应用程序,旨在管理远程服务器上的所有Docker资源。它是对命令行工具lazydocker的Web重建,提供完整的功能而不妥协。Isaiah使用Go语言编写服务器,Vanilla JS编写客户端,支持响应式设计,适用于桌面、平板和移动设备。

核心功能

Isaiah支持全面的Docker资源管理,包括:

  • 栈(Stacks):批量更新、暂停、恢复、重启、停止;支持在浏览器中创建和编辑docker-compose.yml文件;检查日志和配置。
  • 容器(Containers):批量停止、删除、重启、更新、清理;支持重命名、编辑、浏览器内打开shell;检查日志、统计、环境变量和配置。
  • 镜像(Images):清理、删除、运行(基于镜像创建容器)、推送新镜像、批量拉取最新镜像;检查配置和层信息。
  • 卷(Volumes):清理、删除;通过浏览器浏览卷文件;检查配置。
  • 网络(Networks):清理、删除;检查配置。

其他特性包括:

  • 内置Docker主机自动发现。
  • 多种认证方式:主密码(明文或SHA256哈希)、前向代理认证(如Authelia/SSO)。
  • 内置终端模拟器,支持服务器和容器内shell。
  • 支持键盘和鼠标导航、搜索、排序、自定义CSS主题。
  • 配置灵活,通过.env文件设置环境变量。
  • 仅使用WebSocket通信,带宽占用低,镜像大小约4MB。

部署方式

Isaiah提供多种部署选项,要求Docker 23.0.0+(栈功能需Docker 26.0.0+):

  • Docker部署:直接运行Docker镜像,支持调试和守护进程模式。
  • Docker Compose部署:提供示例文件(如简单、SSL、代理、Traefik配置)。
  • 独立应用部署:通过安装脚本下载预编译二进制文件,或手动构建(需Go 1.21和Node 20+)。
  • 多节点部署:支持Master和Agent节点架构,Master作为Web界面和代理,Agent通过WebSocket连接到Master,实现分布式管理。
  • 多主机部署:仅需在一台服务器安装Isaiah,通过TCP/Unix套接字直接管理其他Docker主机。

配置

配置通过环境变量在.env文件中设置,关键参数包括:

  • SSL_ENABLED:启用HTTPS。
  • SERVER_PORT:监听端口(默认3000)。
  • AUTHENTICATION_ENABLEDAUTHENTICATION_SECRET:认证开关和密码。
  • TABS_ENABLED:控制界面显示的标签页(如栈、容器等)。
  • COLUMNS_*SORTBY_*:自定义各面板的列和排序。
  • SERVER_ROLEMASTER_HOST等:用于多节点部署。
  • FORWARD_PROXY_AUTHENTICATION_*:集成前向代理认证。
  • 客户端偏好设置可通过CLIENT_PREFERENCE_*参数在服务器端保存。

还支持自定义CSS主题(通过custom.css文件)和键盘快捷键管理参数。

故障排除与安全

  • 常见问题包括Docker版本过低、消息大小限制导致崩溃(可通过SERVER_MAX_READ_SIZE调整)、shell模拟不完善等。
  • 强调安全重要性:必须启用认证、使用强密码、考虑私有网络部署。

贡献与致谢

Isaiah是作者早期开源项目,欢迎贡献改进。项目感谢lazydocker、Heroicons、Melody等开源项目的支持。

Isaiah旨在提供一个轻量级、功能丰富的Docker管理Web界面,替代如Portainer等重型工具,适用于自托管环境。

14. Hardware Virtualization (www.haiku-os.org)

项目概述 该项目旨在通过移植来自DragonFlyBSD的虚拟机监控程序NVMM,为Haiku操作系统带来硬件虚拟化支持(基于Intel VT-x)。主要目标是移植NVMM驱动程序(仅VMX后端)并使QEMU能够通过NVMM加速虚拟机。

已完成的目标

  1. NVMM前端移植:将核心框架移至Haiku。
  2. VMX后端移植:基本完成,仅存少量细节问题。
  3. libnvmm及测试套件移植:完成。
  4. 内核支持EPT:为Haiku内核添加了扩展页表支持。
  5. QEMU适配:已修补QEMU以支持Haiku上的NVMM,并成功通过NVMM虚拟化其他操作系统(如KolibriOS)。

主要技术实现细节

  • 内存管理:这是最复杂和耗时的部分,需要将虚拟机访客内存管理集成到Haiku的虚拟内存子系统中。关键工作包括实现os_contigpa_zalloc()等函数,并重构了访客页错误处理程序。
  • EPT支持:为内核新增了X86GPAtoHPATranslationMapVMVirtualAddressSpace类,并实现了EPTPagingMethod来创建和填充EPT表,以实现接近原生速度的访客物理内存访问。
  • QEMU集成:由于QEMU构建系统仅支持NetBSD,因此需要专门的构建配方和补丁集来使其在Haiku上支持NVMM。

未解决的问题

  1. SVM后端未移植:项目仅聚焦于Intel VMX后端,未实现对AMD SVM的支持。
  2. 部分操作系统无法在QEMU中正常运行:例如Haiku和Xubuntu虚拟化异常。
  3. 真实硬件与嵌套虚拟化行为不一致:存在严重的性能问题,根源曾误判为EPT表格式错误,修正后性能提升但引发了其他新问题。
  4. 启用SMP时QEMU崩溃:在多处理器环境中,虚拟机迁移物理CPU时偶尔会出错。
  5. EPT翻译未及时从TLB刷新:目前通过上下文切换时刷新整个TLB来缓解,但对多CPU虚拟机仍是隐患。

总结 该项目成功为Haiku系统移植了NVMM虚拟化框架的VMX后端核心部分,并使QEMU具备了基本的硬件加速能力。主要技术突破在于实现了内存管理和EPT支持。然而,仍存在多个需要进一步调试和完善的未解决问题,包括系统兼容性、SMP稳定性及TLB管理优化。作者通过该项目深入学习了虚拟化技术、内核分页及系统开发知识。

15. Euclid's Proof that √2 is Irrational (www.mathsisfun.com)

欧几里得利用反证法证明√2是无理数。他首先假设√2是有理数,即可以表示为两个整数p和q(q ≠ 0)的比值形式p/q。通过平方两边得到2 = p²/q²,进而推导出2q² = p²,这表明p²是偶数。由于偶数的平方根仍是偶数,因此p也是偶数,可写成p = 2m(m为整数)。代入原式得2q² = (2m)² = 4m²,简化后q² = 2m²,表明q²为偶数,从而q也是偶数,可写成q = 2n(n为整数)。将p和q的表达式代入假设的√2 = p/q,得到√2 = 2m/2n = m/n,产生了一个比p/q更简单的分数。然而,这一过程可以无限重复,导致分数无限简化,这与有理数必须有最简形式的事实矛盾。因此,假设错误,√2不能表示为两个整数的比,故为无理数。证明中运用了无限下降法,属于反证法的特例,并基于偶数和有理数的相关性质(如偶数的平方为偶数、分数必有最简形式)进行推理。

16. Do low-level optimizations matter? Faster quicksort with cmov (2020) (cantrip.org)

这篇文章探讨了在现代CPU架构下,低级优化对快速排序算法性能的影响,核心观点是传统的算法分析(比较和交换次数)可能不再完全适用,因为现代硬件的特性(如分支预测、推测执行、缓存行为)对性能有决定性影响。

核心实验与发现:

  1. 基准测试:以1亿个随机整数为数据集,std::sort(C++标准库排序)的平均性能约为每个元素7.3纳秒。基于此计算,算法复杂度系数k约为3纳秒。
  2. 基数排序作为参照:基数排序(256桶)运行时间为1.2秒,展示了基于内存带宽的性能上限。二进制基数排序(2桶)耗时4.8秒,与std::sort的7.3秒接近,为评估std::sort的“通用性”开销提供了参考。
  3. 标准快速排序的瓶颈:一个基础的快速排序实现耗时8.3秒。分析指出,其中依赖于数据比较的条件分支(if (*right <= pivot))在随机数据上会导致约50%的分支预测失败,严重阻碍了现代CPU的推测执行,造成大量性能损失。
  4. 关键优化:消除条件分支
    • 方法:将条件分支(如if语句)转换为无分支的计算序列。例如,使用位掩码和位运算(and/or操作)或利用布尔值作为数组索引,来实现“条件交换”。
    • 效果:使用该方法优化快速排序的partition步骤后,在GCC编译下,运行时间从8.3秒降至5.8秒。进一步使用索引方式优化后,降至4.6秒。
  5. 决定性发现:cmov指令
    • 同样的优化代码,在Clang编译器下运行时间仅为3.6秒,比std::sort快一倍以上。
    • 原因:Clang优化器将上述无分支计算序列识别并替换为x86的cmov(条件移动)指令。cmov指令是真正的无分支操作,不会导致推测执行流水线被刷新,从而极大地提升了在随机数据上的性能。
    • 编译器差异:GCC当时未能识别并生成cmov指令,甚至对类似的手动三元表达式优化也会回退到使用低效的分支。这是导致两个编译器生成代码性能巨大差异的主要原因。

现代CPU的启示:

  • 硬件特性至关重要:现代CPU的深度流水线、多级缓存、复杂的分支预测器和推测执行能力,使得指令的实际执行效率远比理论算法复杂度模型所描述的要复杂。
  • 分支预测是关键瓶颈:在数据模式随机的场景下(如排序大量随机数据),依赖数据的条件分支成为性能杀手。优化的核心目标是保护推测执行流水线,避免因预测失败而清空流水线。
  • cmov指令的潜力与挑战cmov是处理此类问题的硬件原语,但编译器对其使用非常谨慎,因为它在某些情况下(如后续操作依赖结果)可能反而比分支预测更慢。自动识别“适合cmov”的模式是编译器优化的一个难点。

结论与建议:

  • 低级优化确实重要:在追求极致性能时,必须考虑CPU微架构特性。一次成功的无分支优化可带来超过2倍的性能提升。
  • 对标准库和编译器的建议
    • 标准库应提供“分支感知”的排序算法版本(如std::sort),作为默认选项,尤其是在处理小型数据类型时。
    • 标准库中应加入一个标准的、无分支的std::swap_if工具函数。
    • 编译器优化器应努力识别并自动生成cmov等无分支代码模式,从而让大量现有代码无需修改就能获得性能提升。
  • 更广泛的启示:程序员应意识到,现代硬件性能的“舞蹈”需要算法、数据布局和对底层硬件理解的共同配合。有时,基于性能测量的简单代码改变,能带来戏剧性的效果。
17. Async2 – The .NET Runtime Async experiment concludes (steven-giesel.com)

Async2:.NET 运行时异步实验总结

.NET 团队开展了一项名为 async2 的实验,旨在开发一种新的 async/await 模式实现,以提升效率和灵活性。该实验始于对绿色线程的探索,最终转向了将 async 和 await 移至运行时层面的研究。

实验起点:绿色线程及其放弃

  • 概念:绿色线程是由运行时库或虚拟机管理的用户态线程,比内核线程更轻量级,开发者无需直接管理线程。其内存分配在堆上。
  • 关键挑战与放弃原因
    1. 绿色线程与现有异步模型的交互复杂。
    2. 与原生代码互操作比使用常规线程更复杂且更慢。
    3. 与影子栈等安全缓解措施存在兼容性问题。
    4. 难以确定在重要场景中绿色线程能否比现有 async 更快。 因此,绿色线程方案被放弃,并催生了 async2 实验。

async2 实验:将异步移至运行时

  • 核心目标:将 async/await 从编译器特性转变为运行时特性,使运行时能对该模式进行更精细的控制,从而实现更高的效率和灵活性。
  • 关键语义变化
    • 上下文处理:async2 不会在函数边界自动保存或恢复 SynchronizationContextExecutionContext,允许调用方观察到其变化。
    • AsyncLocal 的影响:这将显著改变 AsyncLocal 的行为。在当前实现中,深处的 AsyncLocal 值变更不会影响上层调用方;而在 async2 下,这种变更会向上“泄露”,从而得到不同的输出结果。
  • 与现有 async 的性能对比
    特性 当前 async async2
    性能 通常较慢,深层调用栈更明显 通常更快,在非挂起场景下性能接近同步代码
    异常处理 缓慢低效,会导致 GC 暂停并影响应用响应性 处理方式改进,减少了对应用响应性的影响
    栈深度限制 受栈深度限制,深层调用可能出问题 无明确栈深度限制,能更高效地处理深层调用
    内存消耗 通常更低(尤其在存在大量挂起任务时) 更高(因需捕获整个栈帧和寄存器),但仍可接受

结论与未来展望

async2 是一项初步实验,可能需要数年时间才能达到生产就绪状态。未来若要取代现有 async,必须考虑新旧实现之间的互操作性。尽管前路漫长,但这为 .NET 异步编程的未来奠定了一个良好的基础。

18. A 20-part deep dive into how linkers work (2008) (lwn.net)
19. GPU utilization can be a misleading metric (trainy.ai)

文章指出,GPU利用率(GPU Utilization)常被机器学习团队用作衡量GPU使用情况的主要指标,但该指标存在误导性。它仅反映在采样时间内是否有内核在GPU上执行,并不表明计算核心是否被充分利用。极端情况下,仅进行内存读写操作(不进行任何浮点计算)也能达到100%的GPU利用率。

作者团队在优化一个基础模型公司的LLM训练时发现,尽管通过调整数据加载器、使用混合精度、采用融合优化器和高性能硬件将GPU利用率提升至100%,但模型浮点运算利用率(MFUs)仅约20%,远低于当前LLM训练通常能达到的35%-45%的水平。这揭示了GPU利用率与实际计算效率之间的巨大差距。

为了深入诊断,团队使用Pytorch Profiler进行分析,发现Softmax内核虽然GPU利用率高,但SM效率(SM Efficiency,即流式多处理器活跃比例)很低。SM效率能更准确地反映GPU计算资源的利用情况。例如,一个内核持续运行但仅使用单个SM,虽能达到100% GPU利用率,但SM效率可能极低。

基于此,团队通过融合Transformer块中的关键层(如Softmax、MLP、层归一化与残差连接等)来优化性能。他们采用了已有的高效融合内核库(如Flash Attention)实现,而非自行编写CUDA内核。最终,训练速度提升了4倍,MFUs从20%提升至38%。

文章总结建议AI团队在监控GPU集群时,应同时跟踪SM效率和GPU利用率,以更全面评估GPU性能。虽然计算MFUs是理想的,但其计算复杂且难以进行分层实时监控。更精细的指标如SM占用率(Achieved Occupancy)也能提供进一步洞察,但理解起来更复杂。作者推荐参考Pytorch Profiler博客、DCGM文档及NVIDIA Nsight相关指南以进一步学习。

20. Bioaccumulation of Microplastics in Decedent Human Brains (www.ncbi.nlm.nih.gov)

微塑料在人体大脑中的生物蓄积研究摘要

研究背景

全球环境中微塑料和纳米塑料浓度持续上升,引发了对人类暴露及其健康后果的担忧。既往研究多采用可视化和光谱方法,但对纳米塑料的定量能力有限。本研究采用更先进的热裂解气相色谱-质谱联用技术,对死后人体样本中的微塑料进行分离和定量,旨在比较其在肾脏、肝脏和大脑中的积累情况。

研究方法

  • 样本来源:与美国新墨西哥州法医办公室合作,获取了来自2016年和2024年的去标识化尸检样本,包括肝脏、肾脏和额叶皮层脑组织。共涉及2016年27例样本(17男10女,平均年龄50岁)和2024年24例样本(13男11女,平均年龄52.3岁)。
  • 分析技术
    • 热裂解气相色谱-质谱联用技术:对福尔马林固定的组织样本进行消解、超速离心富集聚合物固体,然后分析12种特定聚合物(包括聚乙烯、聚氯乙烯、尼龙等)。
    • 辅助验证:使用透射电子显微镜观察颗粒形态,并采用衰减全反射-傅里叶变换红外光谱对部分脑样本进行确认。
  • 数据处理:结果以聚合物质量浓度表示,并进行统计分析。

主要发现

  1. 大脑是微塑料的主要蓄积器官

    • 2024年样本中,大脑的微塑料平均浓度高达4,806 μg/g(最高可达8,861 μg/g),分别是肝脏(465 μg/g)和肾脏(666 μg/g)浓度的10倍和7倍以上。
    • 大脑中的微塑料浓度显著高于其他组织。
  2. 浓度随时间显著增加

    • 从2016年到2024年,大脑和肝脏中的微塑料总浓度均显著上升(大脑从3,057 μg/g升至4,806 μg/g)。
    • 在所有被检测的12种聚合物中,聚乙烯是主要成分,其在大脑中的相对比例(74%)也高于肝脏和肾脏。
  3. 微塑料的物理特征

    • 透射电子显微镜显示,分离出的颗粒大多为纳米级(长度常小于200 nm),呈碎片状,表明是老化、易碎的聚合物残留物。这与常见的球形聚苯乙烯微珠模型不同。

讨论与机制推测

  • 大脑蓄积的可能原因:大脑具有极高的脂质含量(仅次于脂肪组织),而塑料的亲脂性可能促使其在脑内积累。此外,大脑接受高比例的心输出量,且纳米颗粒可能通过与胆固醇的相互作用跨越血脑屏障。
  • 与环境暴露的关联:研究认为,随着环境中微塑料浓度的指数级增长,人体内的最大蓄积浓度也将相应增加。这一趋势在本研究中得到了证实——过去八年间,大脑中的塑料总质量浓度增加了50%以上。
  • 健康意义:作者指出,本研究发现的大脑微塑料浓度上升趋势与全球阿尔茨海默病等痴呆症发病率的上升在时间上存在平行关系,并引用研究表明阴离子纳米塑料可能促进蛋白质聚集,这增加了理解微塑料对人类健康影响的紧迫性。

研究局限性

  • 分析方法尚在完善中,样本处理过程中的污染风险需要严格控制。
  • 两个实验室间测量结果存在约25%的变异系数。
  • 每个器官仅取一个样本,组织内部分布的异质性尚未明确。
  • 将浓度数据与健康结局直接关联,需要更大规模的队列研究和更复杂的设计。

核心结论

本研究证实,微塑料和纳米塑料会选择性地在人体大脑中蓄积,且其浓度在2016年至2024年间显著上升。聚乙烯是大脑中积累的主要聚合物,颗粒以纳米级碎片状为主。研究结果凸显了环境中塑料污染加剧对人类神经系统的潜在风险,并呼吁对此进行更深入的研究。

21. Ethernet History Deepdive – Why Do We Have Different Frame Types? (lostintransit.se)

以太网帧类型历史解析:为何存在多种帧格式?

以太网发展历史上主要存在三种帧封装格式:Ethernet II802.2 LLC802 SNAP。这种多样性源于标准化过程中的技术分歧与历史演变。

1. 以太网的起源与DIX联盟

  • 1976年:Robert Metcalfe和David Boggs在施乐帕洛阿尔托研究中心(Xerox PARC)发表论文,描述了早期以太网设计,使用8位地址和16位类型字段。
  • DIX联盟成立:1979年,DEC、Intel和Xerox组成DIX联盟,推动以太网商业化。1980年9月,他们发布了Ethernet Version 1(“蓝皮书”),定义了现代以太网头的基本结构:6字节源/目的地址、类型字段和4字节FCS。

2. IEEE标准化进程与技术分歧

  • Project 802成立:1979年,IEEE启动802项目以标准化局域网技术。DIX于1980年将以太网提交至IEEE,但遭到其他厂商(如IBM、通用汽车)反对,主要争议包括:
    • CSMA/CD的非确定性访问机制与令牌传递的竞争。
    • 对总线拓扑、高负载性能及碰撞处理的担忧。
  • 802项目分裂:由于无法达成统一标准,802项目分为三个子委员会:
    • 802.3:CSMA/CD(以太网)
    • 802.4:令牌总线
    • 802.5:令牌环

3. 三种帧类型的形成

(1) Ethernet II

  • 定义:DIX于1982年发布的Ethernet Version 2,成为事实标准。
  • 结构:14字节头(6字节目的地址、6字节源地址、2字节类型字段),后接46-1500字节数据和4字节FCS。
  • 特点:直接使用类型字段(如0x0800代表IPv4)标识上层协议,简洁高效,成为主流用户数据帧格式。

(2) 802.2 LLC(逻辑链路控制)

  • 设计目标:IEEE为使MAC层(如802.3、802.4、802.5)对上层透明,参考HDLC协议设计了LLC层,作为统一数据链路子层。
  • 结构:在MAC帧后添加LLC头,包含:
    • DSAP/SSAP(各1字节):服务访问点,用于标识上层协议。
    • 控制字段(1字节):沿用HDLC的帧类型标识。
  • 局限性:DSAP仅6位可用(共64个值),远少于Ethernet II的16位类型字段(65536个值),难以支持大量协议。

(3) 802 SNAP(子网访问协议)

  • 产生原因:为解决LLC的SAP地址不足问题,IEEE在802.1中定义SNAP扩展。
  • 结构:当DSAP/SSAP设为0xAA(标识SNAP)时,后接5字节SNAP字段:
    • 3字节OUI(组织唯一标识符)
    • 2字节协议标识符
  • 用途:允许厂商通过OUI自定义协议(如思科的PVST+),常用于控制协议(如STP BPDU),但增加8字节开销,效率低于Ethernet II。

4. 标准化竞争与最终格局

  • ECMA的介入:1981年,欧洲计算机制造商协会(ECMA)采纳了接近DIX的CSMA/CD方案,推动IEEE调整标准。
  • 并存与分化:最终,Ethernet II因简单性成为用户数据主流;LLC/SAP用于需要与OSI模型兼容的场景;SNAP成为协议扩展方案。尽管IEEE标准(802.3)兼容LLC,但实际部署中Ethernet II占据主导。

总结

三种帧类型的存在是历史标准化竞争的结果:DIX推动的Ethernet II以简洁性胜出,IEEE设计的LLC旨在实现MAC层透明但受限于地址空间,SNAP作为LLC的补充提供了协议扩展能力。如今,Ethernet II广泛用于用户数据,而LLC/SNAP主要用于特定控制协议。

22. Beastie Boys dismantled their gold record plaque (djmag.com)
23. SIMD Matters: Graph Coloring (box2d.org)

SIMD与图着色在物理模拟中的应用

游戏开发中SIMD的挑战

SIMD(单指令多数据)在游戏开发中被视为提升CPU性能的终极目标,但实际应用面临诸多困难。传统观点认为,实现真正的SIMD增益很困难。开发者常试图构建基于SIMD的数学库以求性能提升,但效果往往未经证实。例如,游戏玩法程序员常进行零散的向量数学运算(如玩家绳索摆动或游泳),这些代码难以有效聚合为SIMD指令。游戏物理模拟也类似,用户常需创建或销毁单个物体,射线检测方向各异,即使存在大量相似计算,也难以将对象同时聚合处理。

以大型金字塔场景为例:包含5050个刚体和14950个接触对(每个接触对有两个接触点),每个接触点需计算非穿透力和摩擦力,总计需计算59800个力!这些力还需在时间步长内多次计算。另一个关键瓶颈是:每个约束作用于不同物体,即使约束在数组中连续排列以加快迭代,物体仍需随机访问——这成为物理模拟的最终性能瓶颈。

图着色解决方案

为Box2D v3.0的接触力求解引入了图着色技术。其核心思想是为所有接触约束分配有限数量的“颜色”,限制是:在同一种颜色中,一个刚体最多出现一次或不出现。例如,金字塔场景中使用红、橙、黄、绿四种颜色着色接触约束,同色约束可同时求解而不会出现竞争条件。

即使在大型场景中,图着色也能有效扩展。大型金字塔的接触点着色后,每种颜色包含的约束数如下:

  • 颜色1: 2524个约束
  • 颜色2: 2508个约束
  • 颜色3: 2465个约束
  • 颜色4: 2376个约束
  • 颜色5: 2286个约束
  • 颜色6: 2107个约束
  • 颜色7: 652个约束
  • 颜色8: 32个约束

这些颜色组可用于SIMD并行求解。例如,颜色1的2524个约束可同时处理,因为图着色保证了同一刚体不会在同色约束中重复出现。

Box2D中的高效实现

图着色是否复杂缓慢?Box2D采用简单贪心算法:维护每个图颜色的位集(bitset),每位对应一个刚体索引。约束创建时,检查各颜色的位集,分配至首个两刚体位均为0的颜色,然后将两位置1。约束移除时清除对应位。此过程非常高效:

// 约束分配到颜色(核心逻辑)
b2AddContactToGraph:遍历颜色,找到首个两刚体位均为0的颜色,设置位并记录颜色索引。

// 从颜色移除约束
b2RemoveContactFromGraph:根据约束记录的颜色索引,清除对应刚体位。

此外:

  • 刚体休眠时从图着色中移除,唤醒时根据连接的约束重新添加。
  • 静态刚体不设置位,减少所需颜色数。
  • 图着色状态跨时间步长持久化,避免每帧重新计算。

SIMD化求解

得到2524个可并行求解的约束后,将其拆分为4或8个约束块(对应SSE2/Neon或AVX2)。采用“宽浮点”类型(如__m128),将4或8个物体的速度收集到“宽物体”结构中,然后进行类似标量数学的SIMD运算:

// 宽向量点积示例
b2FloatW b2DotW(b2Vec2W a, b2Vec2W b) {
    return a.X * b.X + a.Y * b.Y; // 同时计算4/8个点积
}

求解后,再将宽物体速度散射回各个标量物体。这种收集/散射操作需要特定指令集支持(SSE2/Neon/AVX2),但设置完成后效果显著。

性能评估

Box2D基准测试结果(大型金字塔场景,4个工作线程):

  • AVX2:1117 fps (0.90 ms)
  • Neon (Apple M2):1058 fps (0.95 ms)
  • SSE2:982 fps (1.02 ms)
  • 标量 (AMD):524 fps (1.91 ms)
  • 标量 (M2):679 fps (1.47 ms)

结论

  • SSE2比标量实现快约2倍。
  • AVX2比SSE2再快约14%。
  • Apple M2性能卓越。
  • 碰撞检测仍用标量数学,若能SIMD化可进一步提升性能。

编译器自动向量化的局限

实验发现,即使数据结构(标量实现中的宽浮点结构)已完美排列,编译器自动向量化的效率仍不及手写SIMD代码。这表明在x64架构下,所有数学本质上都是SIMD数学,但低效的SIMD实现无法与优化手写代码竞争。

总结

尽管实现SIMD并行求解需要较多工作(如图着色、数据收集/散射),但Box2D的实践证明其能带来显著性能提升,使游戏能处理更多刚体。图着色是解决物理约束并行求解的关键技术,配合简单高效的算法(如贪心着色)和跨帧状态持久化,可在实际游戏引擎中有效应用。

24. Turnstyle – An esoteric, graphical functional language (jaspervdj.be)

Turnstyle 是一个基于图形的深奥函数式编程语言,其设计灵感来源于对 Piet 语言的观察与改进。

设计动机与核心理念:

  • 汲取与改进:作者欣赏 Piet 中使用区域表示数值字面量、利用色调和亮度作为循环的巧妙设计,但认为其存在颜色数量有限、代码复用困难、难以扩展新原生操作等不足。
  • 基于 Lambda 演算:为了构建更强大的基础,Turnstyle 以 Lambda 演算为理论核心,旨在实现一个最小化的规范,并允许在实现基本交互操作的同时,尽可能复用已编写的代码。

关键特性与发现:

  • 扩展的表达能力:Turnstyle 实际上比标准 Lambda 演算更具表达能力,因为它能够构建抽象语法图(而不仅仅是语法树)。这使得例如递归这样的操作可以无需不动点组合子而直接实现(如示例中的循环所示)。
  • 目标:寻求一种尽可能简单、同时能涵盖扩展了原语(以允许计算机交互)的 Lambda 演算的规范。

项目状态:

  • 该语言已有完整的规范说明、可供运行的示例以及公开的源代码仓库。
  • 作者提供了详细的规范文档、示例和相关的网站与 GitHub 资源链接。
25. Google Play will no longer pay to discover vulnerabilities in Android apps (www.androidauthority.com)

Google Play将终止Android应用漏洞发现奖励计划

核心消息

Google宣布将于8月31日终止Google Play安全奖励计划,该计划自2017年起为安全研究人员提供报酬,以发现并负责任地披露热门Android应用中的漏洞。

计划历史与演变

  • 启动阶段(2017年10月):最初仅限少数开发者参与,漏洞奖励上限为5000美元(远程代码执行漏洞)和1000美元(数据窃取漏洞)。
  • 扩展阶段(2019年):覆盖范围扩大至Airbnb、阿里巴巴、亚马逊、Dropbox等众多热门应用,并开放至所有安装量超过1亿次的Google Play应用。奖励上限提高至20000美元和3000美元。
  • 影响:据2019年数据,该计划的自动化检查帮助超过30万开发者修复了超100万款应用,提升了Play商店的整体安全性。

终止原因

Google在给研究人员的邮件中表示,由于“Android操作系统安全性和功能加固的整体提升”,研究人员报告的可操作漏洞数量减少,因此决定终止计划。Google强调将继续通过其他项目(如Android和Google设备安全奖励计划)与安全社区合作。

历史数据

  • 截至2018年9月:报告30余个漏洞,支付超10万美元奖励。
  • 截至2019年8月:累计支付超26.5万美元奖励。
  • 后续支付总额未公开,但预计远高于26.5万美元。

潜在影响

积极方面:表明热门应用的安全性已显著提高。 消极方面:可能减少安全研究人员未来负责任披露漏洞的动力,尤其针对未运行自有漏洞奖励计划的应用开发者。

27. Crypto 'pig butchering' scam wrecks bank, sends ex-CEO to prison for 24 years (www.cnbc.com)
28. Mourning and moving on: rituals for leaving a career (2014) (franceshocutt.com)

本文作者Frances Hocutt回顾了自己放弃有机化学研究生涯的经历,重点探讨了离开职业时所需的仪式与哀悼过程。作者认为,尽管拥有经济支持和职业经验,离开一个曾投入大量心血的领域仍是一次深刻的身份认同危机,意味着失去了既定的职业路径和“科学家”的自我认知。化学学术界存在清晰的职业地图(如从本科到行业、学界或国家实验室),但离开这条路则被视为“失败”,缺乏社会认可的过渡仪式。

作者指出,人类习惯用仪式标记重要转折,但“离开”这一行为往往没有被仪式化。为了处理这种失落感,她借鉴家庭哀悼仪式,为自己举办了一场“职业追悼会”。朋友们前来分享食物、饮料和对话,作者公开表达了对过往生涯的感激、对失去的哀伤以及对未来的展望,并带领大家祝酒。这一过程帮助她承认损失、获得社群支持,并重新向前看。

作者强调,离开常规路径同样需要勇气和资源,并鼓励读者在面临类似转变时,可以借鉴这种仪式化的方式,共同标记人生新阶段。文章最后附上了她发出的邀请函,具体说明了追悼会的形式与细节。

30. Kill the Newsletter: Convert email newsletters into Atom feeds (kill-the-newsletter.com)

Kill the Newsletter! 服务摘要

核心功能

Kill the Newsletter! 是一项将电子邮件通讯(Newsletter)转换为 Atom 订阅源的服务。用户通过该服务创建订阅源后,会获得一个专用的电子邮件地址和一个 Atom 源地址。发送到该专用邮箱的邮件会自动转换为 Atom 源中的条目,从而允许用户使用 RSS 阅读器订阅和阅读通讯内容。

使用流程

  1. 创建订阅源:通过网站表单创建,获得专用邮箱和 Atom 源地址。
  2. 订阅通讯:使用获得的专用邮箱地址订阅目标电子邮件通讯。
  3. 阅读内容:将生成的 Atom 源地址添加到 RSS 阅读器中,即可在阅读器中接收并阅读通讯内容。

常见问题与限制

  • 订阅确认:大部分确认邮件会被自动转换为订阅条目,用户可在阅读器中点击确认链接。对于要求回复邮件的确认方式,服务不支持,需用户自行联系出版商或设置邮件转发规则。
  • 访问受阻:部分通讯出版商可能会屏蔽该服务。用户需自行与出版商沟通。替代方案是使用个人邮箱订阅,并设置过滤器将邮件自动转发到 Kill the Newsletter! 的专用邮箱。
  • 隐私与分享不应分享个人生成的 Atom 源地址,因其包含专用邮箱标识,可能被他人恶意利用(如取消订阅、发送垃圾邮件)。应推广服务本身,让用户自行创建订阅源。
  • 内容保留:为避免部分阅读器不支持过大的订阅源,系统可能会在收到新邮件时删除旧条目。
  • 故障排查:如果订阅源未更新,用户可向自己的专用邮箱发送一封测试邮件。若几分钟后出现在阅读器中,则问题出在通讯出版方;否则可向服务方报告问题。
  • 删除订阅源:每个订阅条目底部都包含一个管理链接,可用于删除该订阅源。

对通讯出版商的说明

对于出版商而言,可将 Kill the Newsletter! 视为一个电子邮件服务提供商(类似 Gmail),其特殊之处在于将邮件通过 Atom 源投递给偏好使用 RSS 阅读器的读者。服务本身不进行用户追踪。同时,也建议出版商考虑直接提供自己的 Atom 订阅源。

33. Async hazard: MMAP is blocking IO (huonw.github.io)

总结:内存映射(mmap)的异步编程风险

核心问题

使用内存映射(mmap)进行文件读取,其API虽然像访问普通内存数组一样方便,但底层会执行阻塞式IO。在采用协作式调度(如Rust/Python的async/await、C的手动非阻塞IO)的异步环境中,这种隐式的阻塞会破坏并发性,使“并发”代码实际顺序执行,导致性能下降、资源利用不足和延迟尖峰。

实验验证

作者在macOS M1平台(冷缓存下)进行了基准测试,扫描8个256MB文件。测试配置组合了两种文件读取方式和三种并发模式:

  • 读取方式:传统显式读取 vs. 内存映射(mmap)。
  • 并发模式:异步/单线程、8线程同步、单线程顺序执行。

关键结果

  • mmap + 异步:性能与单线程顺序执行几乎相同(约2.5-3秒),表明异步并发未生效。
  • mmap + 8线程:性能显著提升(约0.75-0.8秒)。
  • 传统IO:无论使用异步还是多线程,性能均优于单线程顺序执行(<0.65秒 vs. 0.7秒)。

技术原因:阻塞的“魔法”

mmap通过虚拟内存机制,将文件映射到进程地址空间。当访问的页面数据未在物理内存中时,会触发页面错误,操作系统需从磁盘加载数据到内存。在此过程中,发起访问的线程会被阻塞(挂起)

在异步环境中,async/await的执行器(事件循环)依赖线程在await点主动让出控制权来实现任务切换。而mmap的访问(如let byte = mmap[index];没有await,因此执行器无法切换到其他任务。一旦阻塞发生,整个执行器线程(及所有它管理的任务)都会停滞,导致并发失效。

风险的隐蔽性

  • API欺骗性:mmap返回的对象可被当作普通字节数组(如&[u8]bytearrayvoid*)使用和传递。下游代码在不知情的情况下可能对其进行随机访问,从而引入隐式阻塞点。
  • 缓存的影响:当数据已在操作系统缓存中时,mmap访问很快(甚至快于传统IO)。但缓存冷启动或数据被换出时,阻塞问题依然存在

结论与建议

  • 风险:在异步编程中滥用mmap,会因隐式阻塞而丧失并发优势,可能使性能退化至接近顺序执行。
  • 适用场景:当文件数据确定已在内存缓存中,或用于短生命周期、顺序访问的小文件时,mmap可能提供更低的开销和更快的速度。
  • 替代方案:在需要异步并发IO的场景,应优先使用真正的异步文件IO API(如Tokio的async read),它们能通过await点实现非阻塞调度。

待探讨问题

文章最后提出了若干开放问题,包括不同平台、磁盘类型、预取指令(prefetch)、madvise/mlock选项以及预读机制对mmap性能和阻塞行为的影响。

34. SwiftUI for Mac 2024 (troz.net)

SwiftUI for Mac 2024 更新概要

本文基于作者在 macOS Sequoia 15.1 Beta 和 Xcode 16.1 beta 环境下的测试,介绍了 WWDC 2023 和 2024 中为 macOS 平台带来的 SwiftUI 新功能与改进。

Xcode 更新

  • 项目结构:Xcode 16.1 默认将项目文件夹视为“文件夹”而非“组”,方便通过 Finder 管理文件,但可能影响项目导航器的自定义排列。用户可手动转换回“组”。
  • 预测性代码补全:需要 macOS Sequoia 和充足内存。目前仍处于早期阶段,基于旧代码训练,生成的代码可能过时(如使用完成处理器而非 async/await)或有缺陷(如忘记调用 resume()),但展现了利用 AI 辅助编写样板代码的潜力。
  • 从剪贴板创建文件:可将代码片段(如一个 struct)剪切后,通过菜单或右键选项直接创建为新文件,自动命名并粘贴内容,极大提升了代码结构化整理的效率。

预览功能

  • @Previewable:允许在预览中直接提供数据,特别是绑定属性(Binding),使得在预览中测试交互式组件(如列表选择)变得更加方便。

窗口管理

  • 单窗口应用:将 WindowGroup 改为 Window 场景,并提供 id,即可移除“新建窗口”菜单项,并使关闭窗口等同于退出应用。
  • 工具窗口 (UtilityWindow):新的窗口场景,主要用于浮动面板或工具栏。其特性包括:浮动于其他窗口之上、默认不获得焦点、按 Escape 关闭、应用非活跃时隐藏、不可最小化。在视图菜单中提供“显示/隐藏”选项。
  • 自定义“关于”窗口示例:通过组合多个新修饰符,实现了高度定制化的窗口:
    • .windowResizability(.contentSize):使窗口大小匹配内容。
    • .commandsRemoved():移除自动生成的菜单项。
    • .defaultWindowPlacement { ... }:精确控制窗口的初始位置和大小(如居中于屏幕)。
    • .restorationBehavior(.disabled):禁用窗口位置记忆功能。
    • .windowStyle(.plain):移除标题栏。
    • WindowDragGesture():使整个窗口可拖拽,并可通过 @GestureState 跟踪拖拽状态以实现视觉反馈(如改变透明度)。

标签页 (TabView)

  • 新语法:从原先在视图后添加 .tabItem 修饰符,改为使用 Tab 视图包裹内容,结构更清晰直观:Tab("标题") { 视图 }
  • 新样式:引入 .tabViewStyle(.sidebarAdaptable) 修饰符,可将标签页展示在侧边栏中并显示图标,适用于标签页较多的情况。

图表 (Swift Charts)

  • 新增绘图类型:支持向量化和函数绘图,例如绘制各种正弦波折线图。
  • 导出改进:图表图像导出功能推荐使用 SwiftUI 的 fileExporter

颜色与渐变

  • 颜色混合:新 .mix(with:by:) 修饰符允许动态混合两种颜色。
  • 网格渐变 (MeshGradient):通过定义网格点及其颜色,创建复杂的渐变效果。可用于背景等场景。

SF Symbols 动画

  • 符号效果:通过 .symbolEffect 修饰符为 SF Symbol 图标添加动画(如弹跳),当绑定的 value 值发生变化时触发动画。

其他说明

  • 作者在示例应用中遇到了一个特定的 macOS 15.1 Beta 崩溃 Bug。
  • 文章强调,尽管 SwiftUI 在多平台趋于一致,但开发者仍需注意不同平台(如 macOS)的设计和交互规范。许多标榜“iOS”的资源同样适用于 macOS 开发。
  • 配套的示例项目可在 GitHub 上获取。