2024-08-05

35 篇热帖

1. Andy Warhol's lost Amiga art found (dfarq.homeip.net)

安迪·沃霍尔于1985年为Commodore Amiga 1000电脑创作的数字艺术作品,被认为遗失了39年后,于2024年7月重新现世。这批作品是当年Commodore委托沃霍尔展示Amiga图形处理能力的产物,其中包含一幅著名的黛比·哈利肖像及沃霍尔的自画像。

作品的重新发现归功于前Commodore工程师杰夫·布鲁特。他不仅是当时活动的技术人员,更是沃霍尔的电脑老师,教会了沃霍尔几乎所有计算机知识。布鲁特保存了一份该图像的印刷品及一个包含八幅沃霍尔数字作品的签名软盘,并已在家展示约20年。

尽管以今天的标准看,这些作品分辨率低、色彩有限(最高640×400像素,同一画面仅能使用32种颜色),但分析表明沃霍尔在色彩选择上颇具匠心,刻意选取对比色并使用混合色,这延续了他传统绘画的风格。Amiga的图像处理能力(如剪切、粘贴、填充)正好契合了他基于照片进行大胆色块创作的艺术手法。

然而,沃霍尔对电脑操作极不熟练,尤其不习惯鼠标,经常忘记左右键功能。在公开演示现场,因光线条件与排练时不同,他的实时创作未能成功,大部分填充操作出错。Commodore最终在宣传视频中使用了排练时的成功版本。而沃霍尔遗产于2014年发现的磁盘中包含更多实验性图像,展示了他学习使用电脑的过程。

文章从艺术教育与产品演示的角度指出,沃霍尔虽挣扎于技术操作,但其作品仍体现了其艺术风格与数字工具的结合。这批作品的重现不仅填补了艺术史的一段空白,也揭示了沃霍尔尝试将传统艺术创作数字化的过程。布鲁特作为保存者,其贡献也得到了肯定。

2. Starting Hospice (jakeseliger.com)

本文是一位癌症患者决定进入临终关怀后的自述。主要内容如下:

决定进入临终关怀及原因 作者因鳞状细胞癌肿瘤持续生长,且近期的放射治疗严重影响了生活质量,已无法参与新的临床试验。身体状况不佳,饱受持续不断的咳嗽、疼痛和下颌麻木等折磨。因此,他与家人决定接受临终关怀服务。

选择临终关怀的目的 这主要是为了他的妻子贝丝。作者身后涉及诸多事务与规则,贝丝需要获得支持和帮助来处理这些后续事宜,以便将精力专注于陪伴丈夫最后的时光。

对终局与遗产的安排

  • 作者表示可能无力再回复消息,处于药物影响下的朦胧状态。
  • 他对自己过往的言论感到满足,并认可泰勒·考文关于临终之言可能并非至理的看法。
  • 贝丝承诺将完成两人共同创作的回忆录并出版,这给她未来的生活提供了目标和动力。同时,他们的女儿雅典娜即将出生。

个人的幸运与请求

  • 作者认为自己虽然患病,但在人生中已足够幸运:找到了灵魂伴侣,并得到了许多帮助。
  • 他最大的请求是希望人们能够支持他的妻子贝丝和女儿雅典娜,主要通过“Go Fund Me”筹款链接进行捐赠,剩余资金将用于女儿的未来。
  • 他提及两家可接受研究捐赠的机构:Arc研究院(专注于复杂疾病研究)和加州大学圣地亚哥分校穆尔斯癌症中心,建议人们可向它们捐款以推动医学进步。

最后的感想 作者引用了自己过往文字中关于生命馈赠的比喻,并感激自己获得了完整而充满爱的人生体验。朋友的鼓励话语“你做得很好”也带给他安宁。

4. How I Program in 2024 (akkartik.name)

2024年的编程方法反思

核心观点:对编程工具与方法的演变认知

作者回顾了从2015年至2024年间对编程工具(特别是测试版本控制)态度的变化,并最终形成了关于构建耐用软件的新见解。

思想演变时间线

  • 2015年:曾极度重视测试、版本控制和分层架构,认为糟糕的抽象和工具使用不足是软件问题的根源,并尝试将这些作为基础约束来设计平台(如Mu1)。
  • 2017-2022年:在Mu和Freewheeling Apps项目中,虽然初期使用了测试,但逐渐发现对它们的依赖减少,甚至在某些部分难以编写测试且运行正常。
  • 2024年(转折点)删除了所有测试,并彻底重写了文本编辑器核心,同时放下了对版本控制(合并冲突)的担忧。这一过程反而产出了更好的程序,促使作者进行深度反思。

对构建耐用软件的新共识

作者总结出以下几点关键认识:

  1. 限定范围:为大量人群构建持久软件极其困难,应专注于自己熟悉的人、事和功能范围(参照邓巴数)。
  2. 警惕短视工具:大多数软件受短期激励驱动。应优先选择无过多标志、易于构建、依赖少、不自动更新的软件,这类耐用软件目前数量稀少。
  3. 上下文敏感性:支持的人员、地点、功能等上下文发生微小变化,都可能极大改变程序的适配性。
  4. 探索未知:由于既有耐用软件稀少,新程序开发常会进入未知领域,开发者可能在某些方向上并不完全清楚如何操作。
  5. 工具的审慎使用:类型、抽象、测试、版本控制等工具是探索未知领域的辅助,应按需使用。我们容易过度依赖自己偏好的工具,而过度使用即构成技术债,会掩盖程序不必要的复杂性、降低其耐用性和适应性。
  6. 重写的价值:当对上下文的理解稳定后,丢弃大量旧代码并从头重写具有重要价值。重写前需将程序的所有目标和场景整体导入思维,目标是能够一次性构建所有部分。
  7. 一次性构建:在完成整体思维导入后,应致力于一次性完成所有构建

对旧方法的评价与未来

  • 作者认为,测试和版本控制在当时阻碍了思维的整体导入和进化:测试让人遗忘关注点,版本控制让人固守过去。
  • 他将自己的旧软件归为“第6层”,而最近的重构工作感觉达到了“第9层”,并指出可能还存在更高的层级。
  • 作者指出,复杂程序可能难以在“第8层”(整体导入思维)实现,这描述了大多数多人编写的软件。但并非所有软件都需要达到“第9层”。
  • 数据导向设计被认为是有助于达到“第9层”的思维方式,强调超越直接数据结构选择,从宏观理解程序的数据访问模式。

总结

作者经历了从高度依赖传统工程工具(测试、版本控制)根据具体项目和理解阶段审慎取舍工具,最终在特定项目(文本编辑器重写)中放弃这些工具并获得成功的历程。他提出构建耐用软件应聚焦于熟悉的小范围上下文,警惕工具过度使用带来的技术债,并强调在理解稳定后勇于整体性重写一次性构建的重要性。

6. Show HN: Free e-book about WebGPU Programming (shi-yan.github.io)

《WebGPU Unleashed》免费电子书简介

写作背景

本书作者Shi Yan编写此书的原因是,近年来图形编程API(如Vulkan、Metal、DirectX 12)相比传统的OpenGL更加碎片化,给初学者带来选择困惑。WebGPU作为新一代Web图形API,具有跨平台可用概念上与其他API相似但更简洁、且存在C++/Rust等原生实现的特点,因此非常适合作为图形编程的入门首选。

书籍核心内容

本书系统讲解使用JavaScript通过WebGPU进行图形编程,主要内容包括:

  • GPU驱动与管线基础:解释GPU硬件交互原理,弥补同类书籍的不足。
  • 基础图形绘制:从绘制三角形开始,涵盖2D渲染与3D场景控制。
  • GPU计算与高级渲染:介绍WebGPU独有的网页端GPU计算能力,以及超越基础三角形的高级渲染技术。
  • 综合实战案例:最终实现高斯溅射渲染——一种结合GPU计算与渲染的前沿3D场景重建技术。

书籍特色

  • 互动网页格式:采用在线教程形式,方便嵌入视频讲解、参考文献链接和可运行代码的在线沙盒。
  • 代码交叉引用:书中文本仅展示关键代码片段,完整示例可通过在线沙盒运行和修改。
  • 支持读者反馈:通过GitHub讨论区收集改进建议。
7. Ask HN: Should we bring software dev in-house?
9. WhenFS: Calender Is Now a File System (github.com)

WhenFS 项目摘要

项目简介

WhenFS 是一个将 Google 日历(Google Calendar)转换为 FUSE 文件系统的趣味项目。它通过将数据分割并分布到大量的日历事件描述和元数据字段中,实现了一个基于日历事件的文件存储概念。

核心功能

  • 文件系统管理:支持从现有的 Google 日历创建文件系统,或从零开始新建。
  • 基础文件操作:支持文件和目录的读取、写入与创建。
  • 文件共享:通过提供日历 ID 和文件系统恢复事件 ID,可以挂载他人的 WhenFS 日历文件系统以共享文件。

工作原理与系统架构

WhenFS 的所有文件系统操作(包括文件、目录、读写和属性管理)均基于对 Google 日历事件的 manipulation(操作)。其系统架构自上而下分为四层:

  1. FUSE 文件系统层:由 fuser 库协助实现,处理底层的文件系统请求。
  2. 直写对象缓存(Write-through cache):位于 FUSE 层之下,用于缓存和优化数据读写。
  3. 抽象数据存储接口:提供统一的数据存储抽象层。
  4. 日历 API 后端:可替换的底层接口,直接与 Google 日历 API 进行交互。

性能与局限性

  • 传输性能:由于依赖日历 API,文件传输速度极慢(例如传输 3 KiB 的文件约需 7 秒,上传速度仅约 400 字节/秒)。
  • 系统稳定性:项目中存在诸多 Bug、边缘情况以及完全未实现的功能,且作者暂无修复这些问题的计划。

项目目的与代码状态

  • 开发初衷:作者开发此项目主要是为了学习 Rust 编程语言和 FUSE 文件系统,同时也出于娱乐目的。
  • 代码质量:代码库较为混乱,包含大量 Hack 技巧、不规范的代码和欠佳的设计决策。作者认为“制造混乱”是学习新事物的必经过程,并鼓励开发者自己动手实践。

使用建议与贡献指南

  • 使用警告:强烈建议仅将此项目用于教育目的或存储极少量数据,禁止滥用 Google 日历等免费服务。
  • 代码贡献:欢迎社区贡献,但贡献者需遵守特殊的贡献者许可协议(CLA),即提交代码时必须附带一个能让作者“微微一笑”的轻松表情包(Meme)。
11. Show HN: Pie Menu – a radial menu for macOS (www.pie-menu.com)

Pie Menu 是一款为 macOS 设计的径向菜单应用程序,旨在通过简化快捷键使用来提升效率。其核心理念是解决用户难以记住或混淆快捷键的问题,提供一种更直观的替代方案。

主要功能与特点:

  • 单一快捷键触发:用户只需记住一个自定义的快捷键组合(例如 ⇧ + z),即可在任何应用程序中打开径向菜单。这避免了记忆多个程序特定快捷键的负担。

  • 径向菜单界面:触发快捷键后,菜单会围绕鼠标光标展开,以环形布局显示当前应用程序的常用快捷键选项,提供类似“馅饼菜单”的视觉体验。

  • 上下文自适应:对于不同应用程序,同一个快捷键会打开相同的菜单界面,但菜单内容会根据当前应用程序自动调整,确保显示相关的快捷选项。

  • 自定义配置:用户可以选择自己偏好的快捷键组合来触发菜单,增强个性化使用体验。

目的与优势: 该应用旨在将快捷键“重新思考”并简化到极致,让用户无需记忆复杂组合,从而节省时间、减少错误。通过一个统一的入口访问多程序快捷键,它降低了使用门槛,特别适合快捷键初学者或希望提升操作流畅度的用户。

推广信息: 作者 Marius Hauken 鼓励用户立即下载 Pie Menu,尝试通过示例快捷键(如按住 ⇧ + z)体验功能,并开始节省日常操作时间。

12. A primer on the current state of longevity research (www.owlposting.com)

长寿研究现状概览

本文总结了自2021年以来长寿研究领域的主要进展,围绕四个核心问题展开。

1. Sirtuins(去乙酰化酶)相关疗法的现状?

  • 背景:Sirtuins曾被认为是衰老的关键调节因子,其活性随年龄下降。提高其活性的策略主要包括补充其依赖的辅酶NAD+(使用NMN、NR等前体)以及使用白藜芦醇等化合物。
  • 现状:该理论已失去动力。2023年的一项综述发现NAD+前体补充剂在临床试验中结果平平,主要对病患群体的健康寿命有微弱改善,并非突破性抗衰老药物。2022年的综述更指出sirtuins作为长寿基因的基础理论可能本身就有缺陷,因此专注于此方向可能误导了该领域。

2. 聚焦长寿的研究机构/资助项目/初创公司是否带来了显著成果?

  • 现状:目前评价为时过早。生物研究耗时漫长,短期内期待回报是不现实的。更重要的是,近年来资金(包括美国国立卫生研究院NIH的专项拨款、以及Impetus Grants、Age1、Altos Labs、Retro Biosciences、NewLimit等机构的大量私人资本)已大量涌入。
  • 评价:这些新机构的目标远大,专注于细胞重编程、低温生物学等可能带来根本性变革的领域,而非仅仅热量限制等生活方式干预。只要研究的问题足够有价值,资金投入就是有意义的。

3. 细胞重编程是否产生了有用成果?

  • 背景:通过导入山中因子(OSKM),可将体细胞重编程为多能干细胞(iPSC),此过程伴随着细胞年轻化。2016年发现的“部分重编程”技术,能在不改变细胞身份的前提下获取年轻化益处,为体内疗法开辟了道路。
  • 挑战:面临多重障碍:① 安全性:重编程过度会导致肿瘤,不足则无效,且不同细胞类型所需剂量和时间不同,精准控制极其困难。② 效果有限:虽能改善某些衰老生物标志物,但无法逆转端粒缩短和DNA突变,在动物研究中主要体现为10-20%的平均寿命延长及健康指标改善。③ 递送难题:如何将治疗因子有效递送至体内特定细胞仍是未解之谜。
  • 进展:在动物模型中效果显著。例如,2023年一项研究通过AAV基因疗法对年老小鼠进行周期性部分重编程,使其剩余寿命延长了109%。目前尚无疗法进入临床试验,但Turn Biotechnologies公司正推进一款用于皮肤科的注射药物,并声称解决了递送问题。其他如NewLimit和Altos Labs等公司也处于研发阶段。

4. 生物钟的现状如何?

  • 背景:生物钟通过生物标志物预测个体的“生物年龄”,为评估衰老干预提供量化终点。类型包括表观遗传钟(基于DNA甲基化)、端粒长度钟、转录组钟和蛋白组钟。
  • 现状
    • 表观遗传钟:有用但复杂。最新研究(2024年)发现,大部分甲基化位点的变化由随机或准随机过程驱动,与细胞功能障碍的关联并非绝对直接。
    • 端粒长度钟:可靠性不足。当前模型认为,端粒的“功能障碍”(如慢性损伤)比单纯的长度更重要,即使端粒较长也可能因损伤导致衰老相关问题。
    • 转录组与蛋白组钟:前景广阔。大量研究证实其与年龄相关的细胞功能障碍、器官衰竭和死亡率强相关。其理论机制之一可能是“短基因表达相对增加,长基因表达相对减少”(长基因更易发生DNA损伤)。
  • 总结:各类生物钟各有利弊,均处于发展完善中。普通消费者目前不宜过度依赖生物年龄测试结果。

核心结论

长寿研究领域正经历深刻转变。老旧理论(如Sirtuins)被证伪,而细胞重编程等新兴方向展现出巨大潜力但仍面临重大挑战。研究资金空前充裕,机构目标宏大,但科学转化需要时间。生物钟作为评估工具虽在进步,但尚无完美指标。总体而言,领域正在向更具前景但更复杂的基础科学问题迈进,距离广泛应用仍有距离。

14. Cortex A73's Not-So-Infinite Reordering Capacity (chipsandcheese.com)

Cortex A73 的有限重排序能力

核心目标与背景

Cortex A73 旨在解决早期 Arm 64 位核心(如 A57)因功耗和发热问题而无法充分发挥性能的困境。其设计核心是强调能效,而非单纯追求高指令级并行(IPC),并引入了一种独特的乱序退休(Out-of-Order Retirement) 机制。这一策略使其成功占领了智能手机 CPU 市场。

独特的乱序退休机制与测试方法

传统的顺序退休机制要求指令按程序顺序离开核心,以确保异常处理时的程序状态一致性。然而,A73 在某些确定不会失败的场景下(例如地址转换和页表项检查均已通过的未完成加载操作),可以提前退休后续指令,从而更早地释放内部资源。 为了准确测量 A73 内部结构大小,测试者改进了方法:使用一个依赖于缓存未命中(cache miss)的、永不跳转的分支来阻塞退休流程。这使得他能够测量出 A73 的内部结构容量。

关键结构变化与容量

与前代 A57/A72 相比,A73 的内部结构有显著变化和缩减:

  1. 寄存器文件
    • 设计变革:放弃了统一的、32位宽的寄存器文件(A57/A72),改为分离的整数寄存器文件(64位宽)和浮点/向量寄存器文件(128位宽)。这种设计降低了端口数量,提高了面积和能效。
    • 容量:整数寄存器有 41 个 条目可用于推测结果;浮点/向量寄存器有 38 个 条目。混合使用时,实际可管理的飞行指令数约为 66-76 条
  2. 加载/存储队列
    • 加载队列:容量巨大,可达 50 个 飞行加载,远超 A72 的 32 条,且实际性能瓶颈通常不在此。
    • 存储队列:容量很小,仅 11 个 条目,且与分支共享。这可能导致在存储或分支密集的代码中,核心前端被阻塞,成为性能瓶颈。
  3. 缺失的传统重排序缓冲区(ROB):测试表明,A73 似乎没有传统意义上独立的、按程序顺序追踪所有指令的 ROB。其重排序能力受到上述具体资源(寄存器文件、存储队列等)的共同限制。

架构权衡与性能表现

A73 的设计做出了明确的权衡:

  • 优势
    • 能效与频率:更小的核心结构带来了更低的功耗,使得 A73 能够在被动散热下达到更高的运行频率(例如 Amlogic S922X 中的 2.2GHz),而 A57 在主动散热下通常只能运行在 1.8GHz。
    • 乱序退休:有效弥补了结构容量的缩减,在某些场景(如视频编码)下,其性能可接近结构更大的 A57。
  • 劣势
    • 缺乏存储依赖预测:A73 无法推测加载是否依赖于先前的存储,导致所有加载必须等待所有先前存储地址计算完成才能执行。这增加了延迟,并对有限的重排序资源造成更大压力。
    • 结构容量限制:在资源密集型场景下,其较小的结构(特别是 11 条目的存储/分支队列)会限制性能,使其落后于前代核心。

总结

Cortex A73 代表了一种通过创新微架构设计(如乱序退休)和针对性结构缩减来优化能效的路径。它不盲目追求高 IPC 或大结构,而是通过在关键处做减法(如去除统一寄存器文件、缩小存储队列),并利用其特有的乱序退休机制来维持竞争力,最终实现了在较低功耗下提供可比甚至更优的综合性能(频率×IPC)。然而,这种设计也伴随着在资源受限情况下性能下降的风险。A73 的成功证明了构建高性能 CPU 并非只有一条道路,平衡效率与性能、根据目标应用场景进行精准取舍至关重要。

16. Age is a simple, modern and secure file encryption tool, format, and Go library (github.com)

age 是一个简单、现代、安全的文件加密工具、加密格式及 Go 语言库。其主要特点包括小而明确的密钥、后量子支持、无需配置选项以及符合 UNIX 风格的可组合性。

主要特性:

  • 后量子支持:可以使用 -pq 标志生成混合后量子密钥,以抵御未来量子计算机的攻击。
  • 多种加密方式:支持使用公钥(age 密钥或 SSH 密钥)、密码短语或对称身份文件进行加密。
  • 多接收者:可通过重复使用 -r 标志或使用 -R 指定包含多个接收者密钥的文件,将文件加密给多个接收者。
  • SSH 密钥兼容:支持加密到 ssh-ed25519ssh-rsa SSH 公钥,并可使用对应的私钥文件解密。通过组合此功能与 -R,可以轻松加密给 GitHub 用户的 SSH 密钥。
  • 密码短语加密:使用 -p 标志可以通过密码短语加密文件,默认会自动生成一个安全的密码短语。密码短语保护的文件在解密时会被自动识别。
  • 检查加密文件age-inspect 命令可以在不解密的情况下显示加密文件的元数据,包括接收者类型、是否使用后量子加密以及有效载荷大小。
  • 生态系统:存在多种互操作实现和插件,例如 Rust 实现(rage)、TypeScript 实现(Typage)、YubiKey 插件等。

安装方法: age 支持多种操作系统和包管理器,例如:

  • macOS/Linux(Homebrew):brew install age
  • Windows:winget install --id FiloSottile.age
  • Alpine Linux:apk add age
  • Arch Linux:pacman -S age
  • Debian/Ubuntu:apt install age
  • 其他系统(如 Fedora、openSUSE、FreeBSD 等)也有相应的包管理器安装命令。 用户也可以下载预编译的二进制文件,或者在拥有 Go 环境的系统上通过源代码构建。

基本用法: 命令行工具的使用模式如下:

  • 加密age -r <接收者> [-o 输出文件] [输入文件]age -p [-o 输出文件] [输入文件]
  • 解密age --decrypt -i <身份文件> [-o 输出文件] [输入文件] 接收者可以是 age 公钥(age1...)或 SSH 公钥。身份文件可以包含 age 密钥或 SSH 私钥。输入默认为标准输入,输出默认为标准输出。
17. Jailbroke my Kindle to use it as an e-ink monitor (gist.github.com)

本文介绍了将Kindle Paperwhite 3改造成电子墨水屏显示器的实践过程,核心步骤如下:

1. 越狱Kindle

  • 主要参考mobileread.com的LanguageBreak教程,但作者自行探索并借助其GitHub仓库进行调试。
  • 关键目标是获得设备的root shell访问权限。

2. 在Kindle上运行监听服务器

  • 编写一个简单的Go程序(约30行代码,源码已丢失),监听8000端口接收图像文件。
  • 接收文件后,调用Kindle内置的eips命令绘制图像,例如:eips -g /tmp/img.jpg -w gc16 -x 128 -y 0(使用部分更新模式以优化显示效果)。

3. 屏幕捕获与图像处理(主机端)

  • 使用macOS的screencapture命令循环捕获屏幕为PNG文件。
  • 通过ImageMagick进行格式转换,调整旋转(270度)、尺寸(810x1448)、色彩(灰度8位,256色),并保存为JPEG。
  • 使用netcat通过USB网络(地址192.168.15.244)将图像传输至Kindle监听端口。

4. 改进方向

  • 当前每帧传输完整JPEG效率较低,尤其在文本编辑器等画面变化小的场景中,数据压缩潜力大。
  • 可基于现有工具(如增量传输)优化性能,无需重新实现复杂协议(如h.264、VNC)。

相关资源

  • 越狱漏洞详情:LanguageBreak利用的漏洞(Mobileread论坛)。
  • Kindle内部机制深度解析。
  • KindleTool工具集。
20. Airlines are running out of 4-digit flight numbers (viewfromthewing.com)

航空公司面临4位数航班号耗尽问题

航空公司使用最多4位数的航班号,理论上最多可分配9,999个航班号(无零号航班)。然而,美国航空、达美航空和联合航空等主要航空公司正面临航班号短缺,尽管它们每天运营大量航班(如美国航空每日约6,700次航班)。

问题根源

  • 代码共享与合作需求:航空公司通过代码共享扩展网络,例如美国航空希望销售合作伙伴(如阿拉斯加航空)运营的航班,导致所需航班号超过9,999个。
  • 行业整合:随着航空业合并,航班号需求增加,加剧了短缺。
  • 技术限制:航空公司计算机系统建于20世纪60年代,基于两位字母代码和四位数航班号,结构类似Y2K问题,修改扩展难度大、成本高,且目前仅三大航空公司面临此挑战。

当前应对策略

  • 节省航班号方法
    • 使用同一航班号分配给多个航班,但确保不会同时在空中(如使用同一架飞机执行往返航班)。
    • 实施“through-flights”和“out and back flight number”系统,使去程和返程共享航班号。
    • 建立模型优化航班号分配,并调整航班号范围(如美国航空将主线航班号扩展至3,139)。
  • 案例:美国航空在员工会议上讨论此问题,网络规划高级副总裁Brian Znotins解释了解决方案,并提到技术投资可能过高,倾向于使用变通方法。

技术挑战与历史背景

  • 系统老旧:基于60年代技术,存储和处理数据时采用缩写以节省空间,例如联合航空精英状态“1K”源于两位数限制。
  • 修改困难:添加第五位航班号需要巨大技术投入,类似Y2K问题,目前仅通过工作 arounds缓解。

例子与未来展望

  • 有趣航班号:航空公司仍使用特殊号码,如美国航空的1776(费城到波士顿)、1492(到哥伦布)、AAA777(到拉斯维加斯)、420(到丹佛)。
  • 增长计划:美国航空CEO Robert Isom表示公司有增长野心,将航班号管理视为长期项目,暗示未来可能寻求新解决方案。

总结:航空公司通过优化现有系统和变通方法应对航班号短缺,但技术限制和需求增长使问题持续存在,未来可能需要技术革新。

21. A cryptographically secure bootloader for RISC-V in Rust (www.codethink.co.uk)

SentinelBoot:基于Rust的RISC-V加密安全引导程序

项目概述

SentinelBoot是一个用于RISC-V架构的、演示性的加密安全引导程序,采用Rust语言编写。该项目由曼彻斯特大学发起,Codethink赞助,旨在通过内存安全原则增强RISC-V启动流程的安全性,并利用公钥加密技术实现安全启动。

核心动机

传统引导程序(如U-Boot)多用C/C++/汇编编写,存在内存安全漏洞风险(如数据泄露、拒绝服务、任意代码执行)。Rust语言通过编译时静态分析(所有权、借用、生命周期)提供内存安全替代方案,且性能开销较低,适合系统软件开发。

Rust的安全特性

  • 所有权:确保每块内存有单一所有者,自动释放以避免内存泄漏。
  • 借用:允许非所有者访问内存,分为不可变借用(可多个并存)和可变借用(独占),防止数据竞争。
  • 生命周期:定义变量和借用的作用域,编译器自动管理内存,避免悬垂指针。

实现流程

1. 硬件初始化(汇编阶段)

  • 编写链接脚本生成ELF格式二进制。
  • 使用RISC-V汇编初始化硬件:处理多线程(HARTs)、设置控制寄存器、禁用中断等。
  • 为集成U-Boot的TFTP功能,添加汇编代码支持监督模式执行。

2. 过渡到安全Rust

  • 串行驱动:实现UART协议,通过内存映射寄存器与硬件交互,封装API以隔离unsafe操作。
  • 内存分配器:实现GlobalAlloc trait,基于双向链表动态管理内存,支持高级数据结构(如向量)。双向链表涉及可变指针(违反借用规则),本项目因单HART运行未完全实现互斥锁保护。

3. 加密验证与启动

  • 完整性验证:使用SHA256哈希内核二进制,解析ELF头计算精确大小,避免额外字节影响哈希值。
  • 身份验证:结合公钥加密,服务器用私钥加密哈希生成数字签名;引导程序用公钥解密并比较哈希,确保内核来源可信且未被篡改。
  • 启动内核:验证通过后,设置HARTID和DTB地址,跳转至内核执行。

4. SHA256加速

  • 利用RISC-V向量加密扩展(2023年9月批准)在QEMU中模拟加速哈希计算,采用SIMD原理提升吞吐量。
  • 因工具链不成熟,向量加密指令需预汇编后集成至Rust代码。

性能与分析

  • 开销:相比示例U-Boot二进制,哈希计算增加20.1%运行时间(约0.27秒)。
  • 二进制大小:生成约70KB二进制,仅为U-Boot(约743KB)的十分之一。
  • 安全代码比例:串行驱动实现约80%代码为安全Rust;向量加密实现约68%为安全Rust(因SHA256需汇编)。
  • 编译时间:约为U-Boot的四分之一(Rust工具链并行优化不足)。
  • 目标支持:在QEMU、VisionFive 2、HiFive Unmatched等平台均可运行。

开发与验证

  • 使用GitHub Actions进行持续集成:验证构建、代码规范(Clippy)及在仿真/实际硬件上的功能。
  • 调试通过Ghidra反编译内核、GDB比对控制流实现正确启动。

结论

SentinelBoot展示了Rust在RISC-V引导程序中提升内存安全与实现加密安全启动的可行性。项目在功能增强的同时保持较低开销(大小缩小90%、性能开销仅20.1%),为未来硬件支持提供基础。

22. Using your Kindle as an e-ink monitor (gist.github.com)

将 Kindle 用作电子墨水显示器

本文介绍了如何将 Kindle Paperwhite 3 改造成一个刷新率为 3.5 fps 的外接电子墨水显示器。

主要步骤

  1. 越狱 Kindle

    • 推荐资源:在 mobileread.com 论坛的 LanguageBreak 帖子中获取指南和工具。
    • 核心目标:以任何方式获得设备的 root shell 权限
    • 作者的经验:LanguageBreak 的 GitHub 仓库在调试时非常有用。
  2. 在 Kindle 上部署监听服务器

    • 编写一个简单的 Go 语言程序,用于监听端口 8000 接收图像文件。
    • 使用 Kindle 内置的 eips 工具将图像绘制到屏幕上。
    • 关键命令示例(部分刷新):eips -g /tmp/img.jpg -w gc16 -x 128 -y 0
    • 建议在第一帧前使用 eips -c 清除屏幕。
    • 作者表示源码已丢失,但程序非常简单(少于30行)。
  3. 电脑端屏幕捕获与传输

    • 使用 macOS 的 screencapture 命令循环捕获屏幕为 PNG 文件。
    • 使用 ImageMagickconvert 命令处理图像:旋转、调整尺寸、转换为 8 位 256 色灰度图,并保存为 JPG。
      • 关键命令:convert /tmp/orig.png -rotate 270 -resize '810x1448!' -type GrayScale -depth 8 -colors 256 /tmp/gray.jpg
    • 使用 netcatnc)将处理后的 JPG 文件通过 USB 网络传输到 Kindle 的监听服务器。
      • 关键命令:cat /tmp/gray.jpg | nc -w 0 192.168.15.244 8000
    • 注意:需根据你的 Kindle 型号调整分辨率,并将 IP 和端口改为实际值。

现状与改进空间

  • 性能:当前实现每帧都传输完整的 JPEG 文件,这在网络传输上效率低下,因为连续帧之间的差异通常很小。
  • 优化思路:无需重新开发如 H.264 或 VNC 等复杂编解码器,利用现有工具即可实现显著优化。
  • 性质:这是一个快速搭建的、用于实验和娱乐的项目,在性能和易用性方面有很大改进潜力。

参考资源

26. Buster: Captcha Solver for Humans (github.com)

Buster:为人类设计的验证码解决工具

Buster 是一款浏览器扩展,旨在帮助用户解决困难的验证码(CAPTCHA),主要通过语音识别技术完成 reCAPTCHA 音频挑战。用户只需点击 reCAPTCHA 验证框底部的扩展按钮即可触发自动解决流程。

开发动机 reCAPTCHA 挑战对许多网络用户构成负担,其难度可能受到用户身体与认知能力、社会文化背景、设备或网络环境的影响。有时,这些挑战对人类过于困难,反而对机器人更“友好”。该项目的目标是通过为用户提供通常由自动化系统所采用的解决方案,来改善网络体验。

客户端应用 为提高扩展的成功率,Buster 提供了客户端应用,用于模拟用户交互。该应用支持 Windows、Linux 和 macOS 系统,用户可根据扩展选项中的说明下载安装,或从代码仓库获取。

许可证 该软件由 Armin Sebastian 于 2018-2026 年间版权持有,并遵循 GNU 通用公共许可证 v3.0 发布。

27. WebGL visual programming editor cables.gl is now open source (cables.gl)
28. Japan stocks plunge as much as 7% as Asia shares extend sell-off (www.cnbc.com)

亚洲股市暴跌:日本股市确认进入熊市,跌幅为历史罕见

日本股市遭遇历史性暴跌

  • 确认熊市:基准指数日经225指数和东证指数从7月11日的历史高点已下跌超过20%,正式进入技术性熊市。
  • 单日表现创历史
    • 日经225指数周一暴跌12.4%,收于31,458.42点,创下自1987年“黑色星期一”以来的最大单日百分比跌幅
    • 其点数下跌4,451.28点,为指数历史最大单日点数跌幅。
    • 东证指数也大跌12.23%,收于2,227.15点。
  • 抹去年内涨幅:暴跌导致日经指数抹去了今年的所有涨幅,转为下跌
  • 权重股重挫:三菱、三井物产、住友商事和丸红等贸易巨头股价均暴跌超过14%,其中三井物产市值缩水近20%
  • 日元走强:避险情绪推动日元兑美元汇率升至1月以来的最强水平,报142.09。

其他亚太市场同步暴跌

  • 韩国:基准KOSPI指数暴跌8.77%,小盘股KOSDAQ指数重挫11.3%。跌幅之大触发了熔断机制,交易被暂停20分钟。
  • 台湾:台湾加权指数下跌逾8%,科技股和房地产股领跌。
  • 澳大利亚:S&P/ASX 200指数下跌3.7%。市场正等待澳大利亚央行货币政策会议结果。
  • 香港与内地:恒生指数下跌1.62%,沪深300指数下跌1.21%,为亚洲市场中跌幅最小。

市场动荡的背景与连锁反应

  • 前一交易日延续:周一的大跌延续了上周五的跌势(当时日经和东证指数已分别跌超5%和6%)。
  • 美国市场影响:上周五美国三大股指全线大跌,因远逊预期的7月就业数据引发经济衰退担忧。纳斯达克指数首先进入修正区间。
  • 其他经济数据
    • 中国7月服务业采购经理人指数(PMI)升至52.1,显示服务业扩张步伐加快。
    • 投资者等待中国、台湾的关键贸易数据以及澳大利亚、印度央行的利率决定。
    • 市场预计澳大利亚央行将维持利率不变,但会密切关注其政策声明。
29. Show HN: Visual A* pathfinding and maze generation in Python (github.com)

Python A* 寻路与迷宫生成可视化项目

项目概述

本项目提供了一个高性能的A*寻路算法实现(基于Andrew Kravchuck的Lisp实现),并结合多种迷宫生成技术,以动态可视化的形式展示算法的工作原理。项目通过多样化的迷宫生成方法,创造出视觉上各异且对寻路算法构成挑战的迷宫环境。

核心功能

优化的A*寻路算法

  • 自定义优先队列:针对基于优先级的节点(f值 = 已走过路径g值 + 启发式估算的剩余路径h值)提取和插入进行了优化。
  • 坐标编码:支持整数和浮点坐标的高效编码与解码,兼顾精度与内存效率。
  • 启发式函数:提供曼哈顿距离、八方向距离、欧几里得距离等多种启发函数,平衡计算精度与效率。
  • 邻居枚举:支持4方向、8方向及自定义移动模式,可处理不同地形和移动代价。
  • 代价函数:包含计算实际移动代价的精确成本函数和估算剩余代价的启发成本函数。

多样化的迷宫生成算法

项目集成了十余种算法,生成各具特色的迷宫:

  • 扩散限制聚集(DLA):模拟粒子随机运动形成聚集结构。
  • 生命游戏:基于元胞自动机规则演化生成迷宫。
  • 一维自动机:应用简单规则从一维行演化生成二维图案。
  • 兰顿蚂蚁:通过简单移动规则产生复杂路径。
  • Voronoi图:基于种子点距离划分空间生成多边形迷宫。
  • 分形分割:递归分割网格生成对称迷宫。
  • 波函数坍缩:基于邻居约束确定单元格状态。
  • 生长树:从起点扩展路径生成迷宫。
  • 地形生成:使用柏林噪声生成类自然地形的迷宫。
  • 音乐化:将正弦波叠加生成迷宫。
  • 量子启发:模拟量子干涉模式生成图案。
  • 艺术化:使用笔触和泼溅效果生成抽象迷宫。
  • 元胞自动机:用自定义规则演化网格。
  • 基于傅里叶:对噪声场进行频率滤波生成平滑图案。
  • 反应扩散:模拟化学反应与扩散过程生成有机图案。

迷宫验证与调整

为确保迷宫的功能性(可解性、连通性、复杂度),项目实现了多种验证和修改技术:

  • smart_hole_puncher:通过策略性移除墙壁确保路径存在。
  • ensure_connectivity:验证并连接所有开放区域。
  • add_walls / remove_walls:调整墙壁密度。
  • add_room_separators / break_up_large_room:分割大空间以增加结构复杂度。
  • validate_and_adjust_maze:执行综合检查并应用调整,是最终质量控制环节。
  • generate_and_validate_maze:集成生成、验证和调整的完整流程。

高级可视化

使用Matplotlib库进行动态可视化:

  • 迷宫结构:清晰区分墙壁与通道,并可自定义颜色。
  • 寻路过程
    • 探索顺序:用颜色梯度动态显示算法探索节点的顺序。
    • 路径发现:实时高亮显示从起点到终点的最终路径。
    • 标记:明确标注起点和终点。
  • 自定义选项:提供丰富的颜色、透明度定制功能。
  • 动画导出:支持将动画保存为独立图像帧或编译为MP4视频。文章附有使用FFmpeg将帧序列组装成视频的详细命令示例。

使用说明

  1. 环境配置:克隆仓库,创建Python虚拟环境并安装依赖项(详见requirements.txt)。项目在Python 3.12(Ubuntu 22)上测试通过。
  2. 运行:执行主脚本,可通过参数配置:
    • 迷宫生成方法(如 dla, wave_function_collapse
    • 网格大小(GRID_SIZE
    • 可视化设置(颜色方案、DPI、FPS等)
    • 输出选项(保存为帧图像或视频)

技术栈与依赖

  • Python 3.x
  • NumPy, Matplotlib, SciPy, Scikit-Image, Noise, Pillow, TQDM, Numba(用于JIT编译)
  • FFmpeg(用于视频编码)
  • 项目遵循 MIT 许可证。
30. A 20-something dethroned dotcom CEO that went to work the counter at McDonald's (2000) (web.archive.org)
31. Postgres stores data on disk – this one's a page turner (drew.silcock.dev)

PostgreSQL 数据存储机制概述

本文旨在深入介绍 PostgreSQL 如何将数据实际存储在磁盘上,揭示数据库内部运作的基本原理。

数据目录结构

PostgreSQL 将所有数据存储在一个数据目录中(默认为 /var/lib/postgresql/data)。该目录下包含多个子目录和文件,用于管理集群的各个方面:

  • base/:核心目录,为集群中的每个数据库包含一个子目录(以 OID 命名)。数据库对象(表、索引等)的实际数据文件存储在此。
  • global/:存储集群范围内的共享系统表数据(如 pg_database)。
  • pg_wal/:存放预写式日志文件,用于崩溃恢复和复制。
  • pg_xact/:存放事务提交状态的元数据日志。
  • postgresql.conf:主配置文件。
  • PG_VERSION:记录数据库主版本号。 其他目录(如 pg_commit_tspg_stat 等)用于存储特定功能的状态或数据,在初始安装时通常为空。

术语与核心概念

  • 数据库集群:单个 PostgreSQL 服务器实例,可管理多个数据库。
  • 事务:作为单个逻辑单元执行的一系列操作。
  • 快照:事务在特定时间点看到的数据库视图。
  • 模式:数据库对象的逻辑命名空间(默认为 public)。
  • 表空间:数据库对象的物理存储位置。
  • 行与元组:行是表中的一个数据记录。元组特指行在某一时刻的不可变版本,是磁盘上实际存储的数据单元。

数据库与表的物理存储

创建新数据库后,会在 base/ 下生成一个以其 OID 命名的文件夹。系统默认会创建 postgrestemplate0template1 三个数据库。

每个表、索引等对象在磁盘上由一组文件表示:

  • 主数据文件(堆文件):以 relfilenode 编号命名(如 16390)。表数据存储于此。对于大型对象,会被分割成多个段文件(默认每段 1GB)。
  • 自由空间映射文件(_fsm:跟踪每个数据页中的可用空间。
  • 可见性映射文件(_vm:记录哪些页中的所有元组对所有活跃事务都可见,用于优化索引扫描和真空处理。

页面(Page)结构

数据文件由一系列固定大小的 页(或块) 组成,默认大小为 8KB。页是 I/O 和内存管理的基本单位。 一个页的结构分为三个区域:

  1. 页头和行指针区:从页的开头向“下”增长。页头包含校验和、指向行指针末尾和空闲空间起始的偏移量等信息。每个行指针指向页内的一个具体元组。
  2. 特殊数据区:从页的末尾向“上”增长。对于表页,此区域通常为空;对于索引页,则存储树结构信息。
  3. 空闲空间:位于行指针区和特殊数据区之间,用于存放新的元组。

元组(Tuple)存储

每个元组存储在页的数据项中。其内容包含:

  • 头部信息:包含元组的元数据。
  • 用户数据:各列的值顺序存储,列之间有元数据字节分隔。
  • 系统列:如 ctid(当前元组 ID,格式为 (页索引, 页内项索引))和用于多版本并发控制的 xminxmax 等事务信息。

更新、删除与清理

PostgreSQL 使用 多版本并发控制 来处理并发。

  • 更新:并非原地修改,而是在表的末尾创建一个新版本的元组,并更新旧版本的 xmax 信息。新版本会获得新的 ctid
  • 删除:同样不立即物理删除,仅通过设置 xmax 标记元组为“已死亡”。
  • 死元组:更新和删除操作会产生不再被任何活动事务需要的旧版本数据,它们占用空间直到被清理。
  • 真空处理:通过 VACUUM 操作回收死元组占用的空间。VACUUM FULL 会重写整个表,压缩数据文件并恢复连续空间。

索引的存储

索引的存储方式与表类似,也是由页面组成。其关键区别在于:

  • 索引页存储的是索引键值指向对应表元组的指针
  • 索引页的“特殊数据区”用于存储 B-tree 索引的节点链接信息

理解存储机制的意义

  1. 深度理解与性能优化:有助于理解查询执行、MVCC 和空间管理,从而更好地进行性能调优。
  2. 数据恢复可能性:在极端情况下(如文件损坏或误操作导致 WAL 丢失),具备底层知识可能辅助进行原始数据恢复。
  3. 技术知识深化:是数据库系统原理学习的重要组成部分。

总结

PostgreSQL 的数据存储建立在层次化的结构之上:数据目录 -> 数据库 -> 对象文件 -> 页面 -> 元组。通过理解这种基于页面的堆存储、元组版本化以及真空清理机制,用户可以更深入地掌握数据库的内部行为,这对数据库管理、开发和故障排查都大有裨益。

32. Japan's Nikkei Posts Biggest Single-Day Fall Since 1987 After Weak U.S. Data (www.wsj.com)
33. Qub – a framework for building websites with QBasic (github.com)

Qub - 使用 QBasic 构建网站的框架

Qub(发音为“cube”)是一个命令行界面(CLI)工具,用于生成基于 QB64(QBasic 的一个更现代变体)构建网站的 Web 服务器和框架。

安装与入门

  • 支持平台:目前仅适用于 macOS 和 Linux。可能兼容 Windows WSL 或 Git Bash,但未经全面测试。
  • 快速安装:可通过设置一个别名(alias)来快速使用 Qub,该别名会下载并执行远程脚本。
  • 手动安装:用户也可以下载脚本文件到本地,审查代码后再设置别名,以增加安全性。
  • 基本命令:安装后,可使用 qub --versionqub --helpqub createqub update 等命令。

创建与运行网站

  1. 运行 qub create 命令,根据提示输入项目域名(同时作为项目文件夹名)并选择是否安装 QB64。
  2. 进入项目文件夹后,使用 ./bin/build 构建网站,然后运行 ./server 启动服务器。
  3. 默认通过 http://localhost:6464/ 访问网站。

项目结构

生成的网站项目结构清晰:

  • bin/:存放构建和服务器可执行文件。
  • qub/:包含核心文件:
    • server.bas:Web 服务器主程序(可通过 qub update 更新,但会覆盖本地修改)。
    • qub.conf:服务器配置文件。
  • web/:存放网站内容。
    • pages/:存放页面 HTML 文件,URL 路由会根据文件路径自动生成(例如 links.html 对应 /links)。
    • static/:存放静态资源(CSS、JS、图片、字体等),通过 /static/ 路径访问。
    • layout.html:网站的标准布局模板,包含动态内容占位符(如 <!--$BODY-->)。

服务器功能

Qub 的 Web 服务器(基于 Yacy 修改而来)具备以下功能:

  • 页面路由
  • 静态文件与二进制文件服务
  • 自定义 404 错误页面
  • 基础的动态变量支持(例如在模板中使用 <!--$YEAR-->
  • 可通过配置文件自定义端口
  • 注意:不支持 HTTPS 或 HTTP2。官方建议在生产环境使用 CloudFlare 等服务进行代理。

开发背景与未来

  • 历史:作者出于对 QBasic 的怀旧之情,并受朋友挑战,使用 QB64 构建了个人网站,随后开发了 Qub 框架以简化他人开发流程。
  • 许可:项目采用 MIT 许可证。
  • 未来计划:改进默认模板、制作教程视频,并计划增加更多功能(如 301 重定向、自定义 500 页面、更灵活的模板支持)。
34. Enum class improvements for C++17, C++20 and C++23 (www.cppstories.com)

C++17、C++20 和 C++23 中枚举类(enum class)的改进

本文回顾了C++17、C++20和C++23标准中针对**枚举类(enum class)**引入的一系列增强功能,旨在提升代码的安全性、可读性和可维护性。

1. 枚举类回顾

枚举类(作用域枚举)提供了类型安全的方式来定义一组命名常量。与传统枚举不同,枚举类不会隐式转换为整数或其他类型,从而防止意外误用。

// 枚举类:类型安全,无隐式转换
enum class Color { Red, Green, Blue };
Color c = Color::Red;
// int i = c; // 错误:无法转换

2. C++17:支持从底层类型的花括号初始化

C++17(P0138)允许使用花括号初始化从底层类型直接初始化枚举类,增强了灵活性,同时保持了类型安全。

enum class Handle : uint32_t { Invalid = 0 };
Handle h { 42 }; // OK,C++17起允许
// process({10}); // 错误:仍需显式类型
process(Handle{10}); // 正确

此前,这需要使用 static_cast。C++17的改进在提供便利的同时,通过仅允许显式花括号初始化保持了安全性。

3. C++20:using enum 声明

C++20引入了 using enum 语法,允许将枚举类的所有枚举项引入当前作用域,而不会丧失作用域枚举的类型安全优势。这显著减少了代码冗余,尤其在 switch 语句或频繁使用枚举项的场景中。

enum class ComputeStatus { Ok, Error, FileError /* ... */ };
// 使用前需重复限定名
switch (s) {
    case ComputeStatus::Ok: /* ... */
    case ComputeStatus::Error: /* ... */
}

// 使用 using enum 后简化
switch (s) {
    using enum ComputeStatus;
    case Ok: /* ... */   // 无需再写 ComputeStatus::
    case Error: /* ... */
}

此特性使代码更清晰、简洁,且不牺牲类型安全。

4. C++23:std::to_underlying 工具函数

C++23标准化了 std::to_underlying 函数,用于将枚举值转换为其底层整数类型。这解决了与存储、比较或互操作 API 对接时的常见需求,使转换更直接、更具表现力。

enum class Permissions : uint8_t { Execute = 1, Write = 2, Read = 4 };
// C++23之前
uint8_t val = static_cast<uint8_t>(Permissions::Read);
// C++23
auto val = std::to_underlying(Permissions::Read); // 更简洁,意图明确

该函数提升了代码可读性,减少了样板代码。

5. 未来展望:C++26 反射

未来可能通过C++26的反射特性(提案P2996)进一步支持枚举,例如将枚举值转换为字符串。目前可通过第三方库(如 magic_enum)实现类似功能。

总结

C++17至C++23对枚举类的改进包括:

  • C++17:允许从底层类型进行花括号初始化。
  • C++20:引入 using enum 以简化枚举项的使用。
  • C++23:提供 std::to_underlying 方便底层值的获取。 这些增强在保持类型安全的前提下,提高了枚举类的灵活性、可读性和实用性。
35. How to Get or Create in PostgreSQL (hakibenita.com)

在PostgreSQL中实现“获取或创建”操作是数据同步中的常见需求,但要正确实现并处理并发、幂等性和表膨胀等问题可能比预期更复杂。本文探讨了多种实现方法,并分析了其权衡。

核心目标与挑战

一个理想的“获取或创建”操作需满足:

  • 幂等性:相同输入应始终返回相同输出。
  • 并发安全:多进程同时操作不会导致错误或不一致。
  • 避免表膨胀:操作不应因死元组而显著增加表和索引的大小。
  • 减少对架构的依赖:尽可能不需要额外的唯一约束或排除约束。

主要方法概述

  1. 基于函数的先查后插

    • 方法:先查询记录是否存在,存在则返回,不存在则插入。
    • 问题:并发时可能产生“竞态条件”,导致唯一约束冲突。
  2. 捕获唯一约束异常

    • 方法:尝试插入,如果发生唯一约束冲突,则查询并返回已有记录。
    • 优点:幂等且并发安全。
    • 缺点:频繁冲突时,插入尝试会产生大量死元组,导致严重的表膨胀。异常日志可能造成干扰。
  3. 使用 INSERT ... ON CONFLICT DO NOTHING

    • 方法:利用PostgreSQL的“投机插入”基础设施,冲突时静默忽略。
    • 优点:幂等、并发安全,且不会产生膨胀(冲突行在物理插入前就被检测并丢弃)。
    • 限制RETURNING 子句只返回成功插入的行,需结合对表的二次查询来获取所有目标行。
  4. 结合 WITH (CTE) 和 RETURNING

    • 方法:在CTE中使用 ON CONFLICT DO NOTHINGRETURNING *,主查询中使用 UNION ALL 合并CTE返回的新行和从表中查出的旧行。
    • 理论优势:理论上可避免二次查询的TOCTOU问题。
    • 并发问题:在 READ COMMITTED 隔离级别下,当并发会话在另一会话提交前尝试插入相同值时,可能会返回空结果集(非幂等)或引发冲突,行为不一致。
  5. 使用 MERGE 语句 (PostgreSQL 15+)

    • 方法:声明式同步,可根据匹配条件执行插入、更新或删除。
    • 优点:无需匹配列上存在唯一约束,语法更灵活,适合复杂同步逻辑。
    • 限制与问题
      • 在PostgreSQL 16之前不支持 RETURNING 子句(17版本计划支持)。
      • 并发下,WHEN MATCHED THEN DO NOTHING 的行为与 ON CONFLICT DO NOTHING 不一致,可能引发唯一约束冲突或插入重复数据(无约束时)。
  6. 分离操作:先插后查

    • 方法:执行 INSERT ... ON CONFLICT DO NOTHING,提交事务后再执行 SELECT 获取完整结果集。
    • 优点幂等、并发安全、无膨胀
    • 缺点:需要两次数据库交互,无法在单条SQL语句中完成,且仍需要唯一约束。

结论与要点

  1. 表膨胀的元凶:依赖捕获唯一约束异常(如 INSERT ... ON CONFLICT DO UPDATE SET col=col)会导致膨胀,因为行先被物理插入。
  2. WITH 子句的可见性:CTE中的数据修改对主查询的其他部分不可见,必须通过 RETURNING 传递数据。
  3. 并发与一致性:在 READ COMMITTED 下,单条SQL语句的解决方案可能无法保证完全的幂等性。当存在严重的写冲突时,最可靠的方案是将操作拆分为“先插入,提交,再查询”。
  4. 约束的权衡INSERT ... ON CONFLICT 需要约束,但能保证无重复。MERGE 不需要约束,但在并发无约束场景下可能产生重复数据。
  5. MERGEON CONFLICT 的差异:二者在处理并发冲突时的行为不同,选择时需谨慎。

实用建议

  • 若目标表有唯一约束且同步逻辑简单,优先使用 INSERT ... ON CONFLICT DO NOTHING,并接受可能需要二次查询。
  • 若需复杂同步或无法添加约束,可考虑 MERGE,但需注意其并发行为和版本限制(如 RETURNING)。
  • 在对一致性和幂等性要求极高的高并发场景下,最稳健的方法是拆分为两个操作:先使用 ON CONFLICT 插入,提交后再查询完整数据。