Changkun's Blog欧长坤的博客

Science and art, life in between.科学与艺术,生活在其间。

  • Home首页
  • Ideas想法
  • Posts文章
  • Tags标签
  • Bio关于
Changkun Ou

Changkun Ou

Human-AI interaction researcher, engineer, and writer.人机交互研究者、工程师、写作者。

Bridging HCI, AI, and systems programming. Building intelligent human-in-the-loop optimization systems. Informed by psychology, philosophy, and social science.连接人机交互、AI 与系统编程。构建智能的人在环优化系统。融合心理学、哲学与社会科学。

Science and art, life in between.科学与艺术,生活在其间。

276 Blogs博客
165 Tags标签
Changkun's Blog欧长坤的博客
idea想法 2026-02-15 15:49:15

Testing the ideas API测试想法 API

Testing the ideas API

The following content is generated by LLMs and may contain inaccuracies.

Testing the Ideas API

Context

This appears to be a technical exploration of an API designed for idea management or knowledge work systems. Such APIs typically sit at the intersection of personal knowledge management (PKM), developer tools, and AI-augmented workflows. The testing phase is critical—it reveals not just whether the API works, but whether its abstractions match how users actually think about and manipulate ideas. This matters now because we’re seeing a proliferation of “tools for thought” that promise seamless capture and retrieval, yet often fail at the crucial middleware layer where ideas need to be programmatically accessible, transformable, and connectable.

Key Insights

API Design as Epistemology: The structure of an ideas API encodes assumptions about what ideas are—atomic units? Networks of relations? Versioned entities? Research on API usability (Myers & Stylos, 2016, “Improving API Usability”) shows that developer mental models often clash with API design. For idea systems specifically, the challenge is even steeper: the API must support both hierarchical organization (folders, tags) and emergent networked thinking (bidirectional links, semantic clustering). Notion’s API launch revealed this tension—its block-based model works for structured data but struggles with fluid ideation.

Testing Beyond Functionality: Traditional API testing focuses on endpoints, response codes, and data validation. But idea APIs require evaluating cognitive friction. Does retrieving related ideas require too many calls? Can you express complex queries (e.g., “ideas tagged ‘AI ethics’ connected to papers from 2023”) elegantly? Tiago Forte’s work on “Building a Second Brain” suggests users need both frictionless capture and flexible retrieval—your tests should measure both.

Observability for Thought: Unlike transactional APIs, idea systems benefit from rich metadata about usage patterns. When testing, consider: Are you capturing creation timestamps, modification history, connection strength? These enable future features like “ideas you abandoned” or “concepts gaining momentum.” The difference between a CRUD API and a thoughtful ideas API lies here.

Open Questions

  • How does the API handle the “idea lifecycle”—from fleeting note to fully developed concept? Can it support progressive elaboration without forcing premature structure?

  • What does versioning mean for ideas? Should the API treat idea evolution as git-style commits, or as continuous transformation where history fades?

测试想法 API

以下内容由 LLM 生成,可能包含不准确之处。

测试想法 API

背景

这是一次对面向想法管理或知识工作系统的 API 的技术探索。此类 API 通常位于个人知识管理(PKM)、开发者工具和 AI 增强工作流的交汇点。测试阶段至关重要——它不仅揭示 API 是否可用,还揭示其抽象是否与用户实际思考和操作想法的方式相匹配。这在当下尤为重要,因为我们正在看到大量"思维工具"的涌现,它们承诺无缝的捕获和检索,却常常在关键的中间件层——想法需要以编程方式被访问、转换和连接的地方——出现问题。

关键洞察

API 设计即认识论:想法 API 的结构编码了关于想法是什么的假设——原子单元?关系网络?版本化实体?API 可用性研究(Myers & Stylos, 2016, “Improving API Usability”)表明,开发者的心智模型常常与 API 设计相冲突。对于想法系统来说,挑战更为严峻:API 必须同时支持层级组织(文件夹、标签)和涌现的网络化思维(双向链接、语义聚类)。Notion 的 API 发布揭示了这一矛盾——其基于块的模型适用于结构化数据,但在流畅的构思方面力不从心。

超越功能性的测试:传统 API 测试关注端点、响应码和数据验证。但想法 API 需要评估认知摩擦。检索相关想法是否需要太多调用?是否能优雅地表达复杂查询(例如,“标记为’AI 伦理’并与 2023 年论文相关联的想法”)?Tiago Forte 关于"打造第二大脑"的工作表明,用户需要无摩擦的捕获和灵活的检索——你的测试应该衡量这两者。

思维的可观测性:与事务性 API 不同,想法系统受益于关于使用模式的丰富元数据。在测试时,考虑:是否在捕获创建时间戳、修改历史、连接强度?这些为未来的功能提供支持,如"你放弃的想法"或"势头渐起的概念"。CRUD API 和一个深思熟虑的想法 API 的区别就在于此。

开放问题

  • API 如何处理"想法生命周期"——从转瞬即逝的笔记到完全发展的概念?是否能支持渐进式细化而不强制提前结构化?

  • 版本控制对想法意味着什么?API 应该将想法的演变视为 git 式的提交,还是视为历史逐渐淡出的持续转变?

idea想法 2026-02-15 12:11:53

PBO Preferential Bayesian Optimization MethodsPBO 偏好贝叶斯优化方法

Looking into different ideas about PBO preferential bayesian optimization

The following content is generated by LLMs and may contain inaccuracies.

Deep Dive: Preferential Bayesian Optimization (PBO)

Context

Preferential Bayesian Optimization operates at the intersection of human-in-the-loop machine learning and decision theory, addressing a fundamental challenge: optimizing objectives that are difficult to quantify numerically but easy to compare relatively. Traditional BO assumes access to explicit function evaluations f(x), but many real-world scenarios—from interface design to material aesthetics to policy selection—only provide comparative feedback (“A is better than B”). PBO matters now because alignment problems in AI increasingly require capturing nuanced human preferences that resist scalar quantification, while foundation models create new opportunities for encoding these preferences at scale.

Key Insights

Dueling bandits meets Gaussian processes: PBO extends the dueling bandits framework by modeling latent utility functions with GPs, enabling efficient exploration in continuous spaces. The seminal work by Chu & Ghahramani (2005) and later González et al. (2017) showed that pairwise comparisons, when modeled through probit or logistic likelihoods, can recover underlying preference landscapes with sample efficiency approaching standard BO. The key technical challenge lies in inference scalability—computing acquisition functions over comparison spaces grows quadratically.

Acquisition function adaptations: While standard BO uses Expected Improvement or UCB, PBO requires specialized criteria. Expected Information Gain (EIG) about the optimum location, introduced by Sadigh et al. (2017) for active preference learning, proves particularly effective. Recent work on Preferential Thompson Sampling (Lin et al., 2022) demonstrates that posterior sampling can match or exceed EIG while remaining computationally tractable through Laplace approximations.

Connection to RLHF: Modern RLHF pipelines (Christiano et al., 2017; Ouyang et al., 2022) are essentially high-dimensional PBO problems where LLM outputs are optimized via human preference comparisons. The Bradley-Terry reward model used in RLHF is a direct descendant of PBO’s pairwise comparison models, though RLHF typically operates in representation spaces rather than direct input spaces.

Open Questions

  • How can we efficiently handle intransitive or inconsistent preferences that violate the utility function assumption, particularly when human feedback reflects contextual or time-varying values?

  • Can meta-learning over preference functions accelerate PBO in new domains by transferring knowledge about how humans structure their comparative judgments across related tasks?

研究关于 PBO 偏好贝叶斯优化的不同想法

以下内容由 LLM 生成,可能包含不准确之处。

深入探讨:偏好贝叶斯优化(PBO)

背景

偏好贝叶斯优化运作在人机协同机器学习和决策理论的交汇点,解决一个基本挑战:优化那些难以用数值量化但易于进行相对比较的目标。传统的 BO 假设可以获得显式的函数评估 f(x),但许多现实场景——从界面设计到材料美学到策略选择——只提供比较性反馈(“A 比 B 好”)。PBO 在当下尤为重要,因为 AI 中的对齐问题越来越需要捕获难以标量化的细微人类偏好,而基础模型为大规模编码这些偏好创造了新的机会。

关键洞察

对决赌博机遇上高斯过程:PBO 通过使用 GP 对潜在效用函数建模,扩展了对决赌博机框架,实现了在连续空间中的高效探索。Chu & Ghahramani(2005)以及后来 González 等人(2017)的开创性工作表明,通过 probit 或 logistic 似然建模的成对比较,可以以接近标准 BO 的样本效率恢复底层偏好景观。关键技术挑战在于推断可扩展性——在比较空间上计算采集函数的增长是二次方的。

采集函数的适配:标准 BO 使用期望改进或 UCB,而 PBO 需要专门的准则。Sadigh 等人(2017)为主动偏好学习引入的关于最优位置的期望信息增益(EIG)被证明特别有效。Lin 等人(2022)关于偏好 Thompson 采样的最新工作表明,后验采样可以通过 Laplace 近似在保持计算可行性的同时匹配或超越 EIG。

与 RLHF 的联系:现代 RLHF 流水线(Christiano et al., 2017; Ouyang et al., 2022)本质上是高维 PBO 问题,其中 LLM 输出通过人类偏好比较进行优化。RLHF 中使用的 Bradley-Terry 奖励模型是 PBO 成对比较模型的直接后代,尽管 RLHF 通常在表示空间而非直接输入空间中运作。

开放问题

  • 如何高效处理违反效用函数假设的不可传递或不一致的偏好,特别是当人类反馈反映的是上下文相关或随时间变化的价值观时?

  • 对偏好函数的元学习能否通过迁移人类在相关任务中构建比较判断的知识来加速新领域中的 PBO?

2023 读书清单

Published at发布于:: 2023-12-31   |   Reading阅读:: 1 min
2023 这一年里发生了很多事情,对应的读物也相较以前有所减少,相比之下除了哲学类的读物之外,其他的书籍其实并没有读完(但并不代表他们都不值得读)。 社哲类 和去年一样,我几乎一闲下来就会开始读一些哲学类的书籍。年初的时候,我和我的博士导师 有就“我是谁”产生过简短的讨论,讨论中他提到了这本书: Who Am I?: And If So, How Many? 这本书非常经典的讨论了三个问题:我可以知道什么?我应该做什么?以及我能期待什么? 结合去年开始对虚无主义的接触,我读完后对自己的答案是:我是我体验的总和,它是独一无二的, 我应该去寻找更多的从未体验过并真正能够让我兴奋的事物,并期待和拥抱这些体验。 随着对身份、意识、还原论与整体论深入了解,我的购书记录中还包括这一本: The Mind’s I: Fantasies And Reflections On Self & Soul 但是似乎我并没有机会能够读完这本。后来还读了海德格尔的《存在与时间》,非常难读,也没有读完: Being and Time: A Revised Edition of the Stambaugh Translation 后来索性买了一本哲学史,开始更加全面的对哲学的历史和发展体系进行了解: The history of philosophy. 除了哲学之外,因为所做研究的关系,进一步对社会学发展起来的社会选择理论进行了解: The Handbook of Rational and Social Choice 管理类 去年我开始在一家德国的公司工作,其中一类频繁和老板讨论的话题就是如何做管理,老板提到过这么几本书, 我都买来读了读: The Manager’s Path: A Guide for Tech Leaders Navigating Growth and Change Team Topologies: Organizing Business and Technology Teams for Fast Flow The Responsibility Process: Unlocking Your Natural Ability to Live and Lead with Power A Philosophy of Software Design, 2nd Edition 其中 Team Topologies 单独聊一聊。很早年的时候其实从微服务架构中了解到过康威定律,但当时只对“软件架构正好反映了组织结构”有所印象,并没有更为深入的了解。其实反过来思考就是,更高的管理层如果不直接参与执行软件的实现,如何来影响软件的架构?一个可用的方法其实就是去设计团队的职能,将一个团队拆分为不同的小团队,各司其职,从而影响最终的实现的软件架构。在 Team Topologies 中有从实践的角度进行了更多的讨论,非常值得一读。
Read More阅读更多 »

2022 读书清单

Published at发布于:: 2022-12-30   |   Reading阅读:: 2 min
转眼又是一年,这一年里奔波在工作和生活之间,主观上感受到人的认知得到了不同程度上的转变。 这一转变得益于自己在这一年里度过的各种读本,对比去年,这一年里我逐渐读了非常多的心理学和哲学相关的书籍, 最早的原因和往年一样是为了给自己的研究有足够多的启发,但越到后来愈发的对哲学上的论辩着迷。 我在这里分享出来,希望能够遇到有着类似经历共同感悟的人一起交流。 社科类 这一年里我将心理学和社会学相关书籍统一归类的到社会科学中,并按照我认为的重要程度进行下面的排序。其中对我认知影响最大的是涉及到的社会选择理论。早年我对社会学一类书籍嗤之以鼻,无知的认为社会科学无非是研究一些不可被逻辑证伪的东西。直到近年来因为博士研究的关系,我开始思考当机器学习算法和人类标注数据上的关系时,开始研究到哲学上的心物二元论,并进而接触到社会的产生机制等学说。在正统的西方理性主义下,机器学习的基本问题被定义到了优化问题的框架下,然而任何优化问题都可以被考虑为一个单目标或者多目标的优化问题,最终转化到如今比较热门的说法:损失函数的最小化问题。当我们只有一个目标时,问题非常简单,即求非凸函数的极值,这样的值在大部分情况下是可以梯度下降的。但当问题来到了多目标时,我们就会遇到所谓的 Pareto Front,这时优化问题会被归结到一个没有单一答案的问题,任何优化过程都被转化为不同优化目标之间的权衡,因为在 Pareto Front 上,任何目标都无法在不牺牲其他目标的情况下获得提升。这一思想在社会选择理论中被展现的淋漓尽致,并且相对突出的从逻辑的角度证明了社会选择和个人选择之间的不可调和性,或者更进一步说,社会的公共认知存在与个人认知的不匹配,从而导致个体差异的消失。而这些内容又紧密的与统计学的基本假设以及哲学认知论紧密相连,非常有趣。 Gustave Le Bon. The Crowd: A Study of the Popular Mind. 1895. Amartya Sen. Collective Choice and Social Welfare. 1970. Kenneth J. Arrow. Social Choice and Individual Values. 1951. Stuart Russell. Human Compatible: Artificial Intelligence and the Problem of Control. 2021. Herbert Gints. Bounds of Reason: Game Theory and the Unification of the Behavioral Sciences (Revised Edition). 2014. Jevin D.
Read More阅读更多 »

2021 读书清单

Published at发布于:: 2022-03-20   |   Reading阅读:: 1 min
终于抽出时间来整理 2021 年的一些阅读清单了。这一年里度过的书越发的倾向于心理学、经济学和传统意义上的统计学。 一方面对我的博士研究有一些帮助,另一方面对我在生活中的经历也确实有所启发。 人文类 Working in Public 是一本 GitHub 的员工所撰写的书,这本书主要谈及了作者观察到的与开源软件生产和维护相关的一些思考。 这本书最早是我从 Vue 作者 Evan 的口中得知,因为自己曾经被开源软件所吸引并长期在开源社区活跃,所以立刻买到了这本书来阅读。这本书里面对我非常有启发的几个点包括从用户增长率和贡献者增长率对开源项目模式的思考(联邦、俱乐部、酒店和玩具模式) 以及开源项目中有关分发平台、维护者、贡献者以及参与者之间的共生关系。阅读这本书的同时,随着自己参与开源社区经历的增加,越发的会将曾经年少无知的对所谓早一辈开源精神的抛到脑后,这本书也从某种意义上解答了我对“参与开源”和“做开源”这两个看似等价的概念究竟意味着什么有了更加透彻的理解。真正想要参与开源,我们常常应该问自己:我们能否在失去当初创建并开发项目热情的情况下,持续保持对软件的后期维护?如果能,哪些物质条件是必须的? Working in Public: The Making and Maintenance of Open Source Software 心理学 这一年里我的研究逐步向人的理性决策靠拢,因此也不可避免的读了一定量的心理学书籍。这些书籍 主要围绕着这两个重要的心理学家展开:Herbert Simon 和 Daniel Kanehman,并逐层递进的展开了 许多现代心理学中有关人类认知的基础理论:有限理性、启发式和决策错误。当我读到并尝试这些看似浅显的概念时, 确实非常的惊叹其中的精妙。虽然这些内容没有使用任何所谓绝对客观的理性分析,但一步一步通过社会学实验来揭露并证明了这些广泛存在的与人相关的缺陷。 Thinking, Fast and Slow Models of a Man: Essays in Memory of Herbert A. Simon The Adaptive Decision Maker Expertise, Communication, and Organizing 统计学 虽然本科的时候自认为统计学得非常的扎实,所以也一直被一些关于显著性检验的方法、似然估计这些频率派和贝叶斯派方法 的思想非常浅显而束缚。但是,真到需要自己的研究需要确定没一个细节时,不得不感叹非常多学科上的细节以及他们的巧思。 这一年里我自认为相对系统的接触了一些有关贝叶斯分析以及因果推断的方法,这些内容大部分从下面的部分书籍中习得, 也进一步补全了我对社会科学中研究的可靠性和批判性的认知。 The Book of Why: The New Science of Cause and Effect Causal Inference in Statistics: A Primer Elements of Causal Inference: Foundations and Learning Algorithms Human-In-The-Loop Machine Learning: Active Learning and Annotation for Human-Centered AI The Art of Statistics: Learning from Data A History of Vector Analysis 工程类 其实从我今天的认知角度来看,工程类的书已经论文最无聊的一类书籍了。这一年里我买到了四本不同程度的工程书籍。 第一本书在国内应该是有中译本的,可以说是了解多线程编程的经典。这本书其实我在本科的时候就有读到过一些内容, 但是当时因为没有足够深入的了解多线程编程的内涵,所以走马观花并没有学进去多少东西。这次买英文的原版来读的主要原因是因为想要更加全面和系统的了解多线程编程,也确实补全了我对共享内存中屏障、事务等一些理论的认识。 其他的几本书买来后其实并没有看完,尤其是后面两本。第一本书里我比较喜欢关于测试的一章,后一本本是因为着手编写渲染引擎时买来做案头参考书的,虽然对实践上只有指导思想,但也非常有启发意义。最后那本有点纯粹 man page 的意味,当时因为需要了解有关内存分配的系统调用所以买来仔细读了读,不过至少也是一本很好的参考书。
Read More阅读更多 »
idea想法 2021-02-15 00:00:00

Daily Readings每日阅读

Read this article:

  • What are the most important statistical ideas of the past 50 years? https://arxiv.org/pdf/2012.00174.pdf

读了这篇文章:

  • 过去 50 年最重要的统计学思想是什么?https://arxiv.org/pdf/2012.00174.pdf
idea想法 2021-02-14 00:00:00

Big Changes in Go 1.17Go 1.17 的重大变化

Runtime changes:

  • New GC Pacer: https://golang.org/issue/44167
  • Scheduler performance: https://golang.org/issue/43997

Toolchain changes:

  • Register-based calling convention: https://golang.org/issue/40724
  • Fuzzing: golang.org/s/draft-fuzzing-design

运行时变化:

  • New GC Pacer: https://golang.org/issue/44167
  • Scheduler performance: https://golang.org/issue/43997

工具链变化:

  • Register-based calling convention: https://golang.org/issue/40724
  • Fuzzing: golang.org/s/draft-fuzzing-design
idea想法 2021-02-10 00:00:00

A New GC Pacer全新的 GC 调步器

Today, the Go team released a brand new GC pacer design. Let’s briefly discuss what problems existed in the previous design and what the new design aims to solve.

The current Go runtime GC is a concurrent mark-sweep collector, which involves two core problems that need to be solved: 1) when to start GC and how many workers to launch for collection, to prevent the collector from using too many computing resources and affecting efficient execution of user code; 2) how to prevent the garbage collection speed from being slower than the memory allocation speed.

To address these problems, as early as Go 1.5, the Go team treated this as an optimization problem of minimizing heap growth rate and CPU usage, which led to two key components: 1) the pacer: predicting GC trigger timing based on heap growth speed; 2) mark assist: pausing user code that allocates too fast, redirecting goroutines that are allocating memory to perform garbage marking work, in order to smoothly complete the current GC cycle.

However, when making pacing decisions, this GC contains a hidden assumption: the allocation rate is always a constant (1+GOGC/100). Unfortunately, due to the existence of mark assist and discrepancies between implementation and the theoretical model, this assumption is actually incorrect. This leads to several hard-to-solve problems: 1) when the allocation rate violates the constant assumption, the predicted start time is too late, requiring excessive CPU consumption — while GOGC can be dynamically adjusted, it remains a hyperparameter requiring extensive domain experience to tune manually; 2) since the optimization targets heap growth without heap memory size limits, either setting GOGC too large or encountering peak allocations causes rapid heap growth leading to OOM; 3) newly allocated memory within the current GC cycle is left to the next GC cycle for collection, and mark assist’s allocation throttling causes latency pauses (STW); 4) …

So what has the new pacer redesigned to solve these problems?

As mentioned above, the main source of various problems is the incorrect assumption that the allocation rate is a constant. So naturally, it’s easy to think of using the mark assist component to dynamically calculate the allocation rate during modeling, thereby achieving the goal of dynamically adjusting the heap target. Unfortunately, the original design only tracked allocations on the heap, without considering the stack or global variables. To make the problem more comprehensive, the new design introduces an “assist ratio” — the ratio of allocations produced but not collected in the current GC cycle (A) to the amount of scanning completed in the current GC cycle (B), i.e., A/B. This metric more intuitively reflects the actual difficulty of GC work: if the user allocation rate is too high, A increases, the assist ratio rises, and more assistance is needed from the mark assist; if the allocation rate is moderate, the assist ratio decreases. With the introduction of the assist ratio, the pacer can dynamically adjust the assist work, thereby resolving the pauses caused by the assist.

Let’s look at a practical scenario: when a sudden burst of peak requests arrives, the number of goroutines increases dramatically, generating a large number of stacks and allocation tasks. Here are the simulation results: Figure 1 shows the pacer before adjustment, Figure 2 shows the pacer after adjustment. As shown in the lower-left of Figure 1, the heap target workload is consistently underestimated, causing the heap to always overshoot; while the new pacer can quickly converge to zero and complete the heap target prediction. The upper-right of Figure 1 shows that the actual GC CPU usage is always lower than the target usage, failing to meet the expected metrics; while the newly designed pacer can quickly converge to the target CPU usage.

Of course, due to space constraints, the above is only a very brief introduction to the new pacer design. If you are interested in this topic, you can refer to the following links. There will be opportunities to share more detailed analysis in the future.

  1. Existing problems with the GC pacer: https://golang.org/issue/42430
  2. Design document for the new pacer: https://go.googlesource.com/proposal/+/a216b56e743c5b6b300b3ef1673ee62684b5b63b/design/44167-gc-pacer-redesign.md
  3. Related proposal: https://golang.org/issue/44167
  4. Simulator for the new GC pacer model: https://github.com/mknyszek/pacer-model

今天,Go 团队发布了一个全新的 GC 的调步器(Pacer)设计。这次就来简单聊一聊这个以前的设计有什么问题,新的设计又旨在解决什么问题。

目前 Go 运行时的 GC 是一个并发标记清理的回收器,这涉及两个需要解决的核心问题:1)何时启动 GC 并启动多少数量的 worker 进行搜集从而防止回收器使用过多的计算资源影响用户代码的高效执行;2)如何防止收集垃圾的速度慢于内存分配的速度。

为解决这些问题,早在 1.5,Go 团队将这个问题视作一个最小化堆的增长速率和 CPU 的使用率的优化问题,从而促成了两个关键组件:1)调步器:根据堆的增长速度来预测 GC 的触发时机;2)标记助理 (Mark Assist):暂停分配速度过快的用户代码,将正在分配内存的用户代码转去执行垃圾标记的工作,以便顺利完成当前的 GC 周期。

然而这样的 GC 在实施调步决策时,包含一个隐藏的假设:分配速率总是一个常数(1+GOGC/100),可惜由于标记助理的存在、实现与理论模型的差异,导致这个假设其实并不正确。进而带来的很难解决的问题:1)当分配速率违反常数假设时,预测的启动时间太晚反而需要消耗过多的 CPU,虽然可以动态的调整 GOGC,但这仍然是一个超参数,人工优化需要大量的领域经验,很难直观的使用这个变量对 GC 进行优化;2)由于优化问题是以堆的增长为目标,由于没有堆内存大小的使用限制,无论是设置过大的 GOGC 或者出现峰值分配时都会导致堆的迅速增长从而 OOM;3)在当前 GC 周期内新分配的内存将留到下一个 GC 周期进行回收,标记助理暂缓分配带来的延迟停顿 STW;4)… 那么新的调步器为解决这些问题做了什么重新设计呢?

正如前面所说,产生各类问题的主要来源是对分配速率为常数这一错误的假设,那么自然也就很容易想到在建模的过程:利用标记助理这一组件来动态的计算分配的速率,从而达到动态调整堆目标的目的。可惜的是原来的设计中标记助理仅统计了堆上的分配情况,而对栈或全局变量没有加以考虑。为了让问题考虑得更加全面,新设计中引入了一个「辅助率」,表示当前 GC 周期新产生但没有回收的分配量(A)与当前 GC 周期完成的扫描量(B)之比,A/B。这一指标更加直观的反应了 GC 的实际工作难度:如果用户分配速率过高,那么 A 将增大,进而辅助率增高,需要助理提供更多的辅助;如果分配速率适中,辅助率下降。根据辅助率的引入,调步器便可动态的的调整助理的辅助工作,进而解决辅助时带来的停顿。

我们来看一个实际的场景:当突然出现大量峰值请求时,goroutine数量大量增加,从而产生大量栈和分配任务,极其模拟的结果:图 1 是调整前的调步器,图 2 是调整后的调步器。可见图1左下角显示,总是错误的低估了堆目标工作量,导致堆总是在过冲;而新的调步器能很快的收敛到零,完成堆目标的预测;图 1 右上角则表明实际的 GC CPU 使用率总是比目标使用率低,从而为能完成预期指标;而新设计的调步器则能很快收敛到目标的 CPU 使用率。

当然,限于篇幅上面只是对新的调步器设计做了一个非常简略的介绍。如果对这个内容感兴趣,可以查阅后面的这些链接,之后有机会再对此设计做进一步详细的分享。

  1. GC 调步器现存的问题:https://golang.org/issue/42430
  2. 新调步器的设计文档:https://go.googlesource.com/proposal/+/a216b56e743c5b6b300b3ef1673ee62684b5b63b/design/44167-gc-pacer-redesign.md
  3. 相关的提案:https://golang.org/issue/44167
  4. GC 新调步器模型的模拟器:https://github.com/mknyszek/pacer-model
idea想法 2021-01-27 00:00:00

Go 1.16 Big ChangesGo 1.16 的重大变化

Go 1.16 has released many very interesting changes. Here is a brief summary:

russ cos: deprecated.

  • https://twitter.com/_rsc/status/1351676094664110082
  • https://go-review.googlesource.com/c/go/+/285378
  • https://github.com/golang/go/issues/43724
  1. Support for darwin/arm64
    1. Issues encountered supporting darwin/arm64
      • Apple’s bug: related to signal preemption
    2. Apple Silicon M1 performance
      • But crypto performance is poor
      • Release cycle: https://github.com/golang/go/wiki/Go-Release-Cycle
    3. Compiler bootstrapping process
  • Installing Go: https://gist.github.com/Dids/dbe6356377e2a0b0dc8eacb0101dc3a7

  • https://github.com/golang/go/issues/42684

    • Kernel Panic Episode 62: Your Computer Isn’t Yours, Code Signing, OCSP Server
    • Ken Thompson Turing Award lecture: Reflections on Trusting Trust
      • TODO
    • Apple’s long-standing code signing issues; I encountered similar problems doing Electron in the early days, and these issues still exist today
  • Asynchronous preemption random crashes, a Rosetta bug: https://github.com/golang/go/issues/42700

  • Bootstrapping, installation confusion: https://github.com/golang/go/issues/38485#issuecomment-735360572

    • Go’s bootstrapping consists of three steps
        1. 1.4 C version TODO
        1. tool chain 1
        1. tool chain 2
        1. tool chain 3
  • Run x86 programs under Rosetta: arch --x86_64

  • M1 compatibility status in dotfiles: https://github.com/changkun/dotfiles/issues/2

    • https://doesitarm.com/
    • https://isapplesiliconready.com/
  • Got it in early December, have been using it for almost two months now — very smooth, battery life is incredible

  • My essential third-party software list:

    • homebrew (compatibility is not great, but fortunately most dependent software is written in Go, and Go’s support is very complete)
      • Breaks compatibility casually, removes software distribution — there was a tool called rmtrash that I had been using since around 2014, but it was removed from distribution last year, so I wrote a fully compatible tool changkun.de/s/rmtrash, but it wasn’t merged; they said it needed to be approved by the original author to bypass popularity restrictions, but the original author is unreachable
    • vscode (have been using Insider long-term)
    • macvim
    • tmux
    • oh-my-zsh
    • Blender (Cycles ray tracing doesn’t support GPU, but editing meshes with less than a million vertices is fine)
    • iTerm: supports M1
    • Chrome: supports M1
    • MacTex: supports M1
    • Docker: released support a week before Christmas, works perfectly, no issues so far
  1. Go Modules changes

    1. Collecting feedback
    2. Complex dependency management — what’s the most complex project dependency you’ve managed in practice, how many modules, and what do you write for each dependency upgrade? What did you use before Go modules?
      1. My experience: Go vendor, 1.10 dep, 1.11 go modules
      2. GOPATH project management — although GOPATH has been removed, I still follow the GOPATH convention
    3. Minimum version selection
      1. Semantic Versioning: major.minor.patch
      2. The classic diamond dependency problem: A depends on B and C, B and C each depend on different versions of D that are incompatible, so no specific version of D can be selected — semantic import versioning eliminates this by adding the major version number requirement at the end of the import path /v2
      3. dep doesn’t allow diamond dependencies, upgrades are very difficult
      4. Build reproducibility — without a lock file, >= dependencies change over time
      5. Select the minimum usable version — builds don’t change over time
      6. https://www.youtube.com/watch?v=F8nrpe0XWRg&ab_channel=SingaporeGophers
      7. Misunderstood working methods
      8. GOPATH
      9. vendor
      10. Three key points
      11. Compatibility
      12. Reproducibility
      13. Cooperation (often overlooked by many)
    4. Go Modules enabled by default, go build must include go.mod file, otherwise compilation fails
    5. build/test will not upgrade modules
    6. Default -mod=vendor
  2. File system interface

    1. Why is the fs.FS abstraction important

      1. Unix file system abstract always disk blocks
      2. Network file systems (Upspin) abstract away machines
      3. REST abstracts nearly anything
      4. cp doesn’t care whether it’s moving file blocks, or even where the file is — it could be different disks or different machines
      5. Defines the “generics” for any file type tools
    2. What major changes it caused

      1. io/ioutil
        1. Russ Cox’s explanation of deprecated in Go (https://twitter.com/_rsc/status/1351676094664110082)
        2. https://www.srcbeat.com/2021/01/golang-ioutil-deprecated/
      2. Other fs abstractions
      3. Rob Pike’s 2016/2017 Gopherfest, Upspin, Changkun’s Midgard
        1. https://www.youtube.com/watch?v=ENLWEfi0Tkg&ab_channel=TheGoProgrammingLanguage
        2. FUSE: filesystem in userspace
        3. https://changkun.de/s/midgard
        4. Every user has a private root, no global root, r@golang.org/some/stuff, user names look like email addresses
        5. Access control defined by plain text files read: r@golang.org, ann@example.com
      4. Currently a very simple implementation, just a read-only file system
      5. ReadDir and DirEntry
        1. https://benhoyt.com/writings/go-readdir/
      6. Extensible directions: memoryFS, support for writing back to disk, hashFS for CDN support
      7. Remaining issues… e.g. 44166
      1
      2
      3
      4
      5
      6
      7
      
      import _ "embed"
      //go:embed a.txt
      var s string
      
      import "embed"
      type embed.String string
      var s embed.String
      
      1
      
      
      
  3. File embedding //go:embed

    1. Basic functionality of the new feature
    2. Some possible applications
    3. Some features discussed during the feature freeze cycle
    4. https://blog.carlmjohnson.net/post/2021/how-to-use-go-embed/
  4. Runtime memory management

    1. Return to MADV_DONTNEED
    • https://blog.changkun.de/posts/pss-uss-rss/
    1. New monitoring infrastructure runtime/metrics
    • Previous monitoring functions: runtime.ReadMemStats, debug.GCStats
    • runtime/metrics:
      • metrics.All()
      • Issue 37112
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package main

import (
	"fmt"
	"runtime/metrics"
)

func main() {
	// Get descriptions for all supported metrics.
	descs := metrics.All()

	// Create a sample for each metric.
	samples := make([]metrics.Sample, len(descs))
	for i := range samples {
		samples[i].Name = descs[i].Name
	}

	// Sample the metrics. Re-use the samples slice if you can!
	metrics.Read(samples)

	// Iterate over all results.
	for _, sample := range samples {
		// Pull out the name and value.
		name, value := sample.Name, sample.Value

		// Handle each sample.
		switch value.Kind() {
		case metrics.KindUint64:
			fmt.Printf("%s: %d\n", name, value.Uint64())
		case metrics.KindFloat64:
			fmt.Printf("%s: %f\n", name, value.Float64())
		case metrics.KindFloat64Histogram:
			// The histogram may be quite large, so let's just pull out
			// a crude estimate for the median for the sake of this example.
			fmt.Printf("%s: %f\n", name, medianBucket(value.Float64Histogram()))
		case metrics.KindBad:
			// This should never happen because all metrics are supported
			// by construction.
			panic("bug in runtime/metrics package!")
		default:
			// This may happen as new metrics get added.
			//
			// The safest thing to do here is to simply log it somewhere
			// as something to look into, but ignore it for now.
			// In the worst case, you might temporarily miss out on a new metric.
			fmt.Printf("%s: unexpected metric Kind: %v\n", name, value.Kind())
		}
	}
}

func medianBucket(h *metrics.Float64Histogram) float64 {
	total := uint64(0)
	for _, count := range h.Counts {
		total += count
	}
	thresh := total / 2
	total = 0
	for i, count := range h.Counts {
		total += count
		if total > thresh {
			return h.Buckets[i]
		}
	}
	panic("should not happen")
}
  1. Other noteworthy features
    1. os/signal.NotifyContext
    2. Memory model fixes
    3. Linker optimizations

Go 1.16 发布了非常多非常有趣的变,尝试做一个简单的总结:

russ cos: deprecated.

  • https://twitter.com/_rsc/status/1351676094664110082
  • https://go-review.googlesource.com/c/go/+/285378
  • https://github.com/golang/go/issues/43724
  1. 支持 darwin/arm64
    1. 支持 darwin/arm64 上遇到的问题
      • 苹果的bug: 与信号抢占有关
    2. Apple Silicon M1 性能
      • 但是在加密上性能很差
      • 发版周期:https://github.com/golang/go/wiki/Go-Release-Cycle
    3. 编译器自举过程
  • 安装 Go:https://gist.github.com/Dids/dbe6356377e2a0b0dc8eacb0101dc3a7

  • https://github.com/golang/go/issues/42684

    • 内核恐慌的第 62 期:你的电脑不是你的,代码签名,OCSP Server
    • ken thompson 图灵奖演讲:reflections on trusting trust
      • TODO
    • 苹果代码签名的老问题,早年做 electron 也是这类问题,现在这样的问题还是存在
  • 异步抢占随机崩溃,是 Rosetta 的 Bug:https://github.com/golang/go/issues/42700

  • 自居,安装的困惑:https://github.com/golang/go/issues/38485#issuecomment-735360572

    • Go 语言的自举分为三个步骤
        1. 1.4 C version TODO
        1. tool chain 1
        1. tool chain 2
        1. tool chain 3
  • 在 Rosetta 下运行 x86 程序:arch --x86_64

  • dotfiles 中关于 M1 的兼容性情况:https://github.com/changkun/dotfiles/issues/2

    • https://doesitarm.com/
    • https://isapplesiliconready.com/
  • 十二月初入手 如今已经使用快两个月了 非常流畅 续航逆天

  • 我的必备第三方软件列表:

    • homebrew (支持性不好,好在现在大部分依赖的软件是用 Go 写的,而且 Go 的支持非常完善)
      • 不考虑兼容性 随意破坏兼容性移除软件分发,有一个 rmtrash 的工具,我从2014年左右就开始使用,但是去年被从软件分发中移除了,所以自己写了一个全兼容的工具changkun.de/s/rmtrash,但没有被合并,他们说了要被原软件作者任何才能不受受欢迎程度的限制,但实际上软件作者已经联系不到了
    • vscode(已在长期使用 Insider)
    • macvim
    • tmux
    • oh-my-zsh
    • Blender(Cycles 光追渲染不支持 GPU,但编辑顶点小于百万级别的网格是没有问题的)
    • iTerm:支持 M1
    • Chrome:支持 M1
    • MacTex:支持 M1
    • Docker:圣诞节前一周发布支持,很完美,至今没有遇到问题
  1. Go Modules 的变更

    1. 收集反馈
    2. 复杂依赖管理,你实践中管理过最复杂的项目依赖多少模块,每次依赖升级都有写什么?在没有 Go modules 之前你用的是什么?
      1. 我的经历:Go vendor, 1.10 dep, 1.11 go modules,
      2. GOPATH 的项目管理,现在虽然移除了 gopath,但我还是沿用了 gopath 的习惯
    3. 最小版本选择
      1. Semantic Versioning: major.minor.patch
      2. 经典的钻石依赖问题:A依赖B和C,BC分别依赖 D 的不同版本,而这两个版本的 D 不兼容,所以无法在依赖中选取一个特定的D版本,semantic import versioning 消除了这种依赖,在import path的最后添加了主版本号的要求/v2
      3. dep 不允许钻石依赖,升级非常难
      4. 构建的可重复性,没有lock文件,>=的依赖会随着时间的变化而变化
      5. 选择最小的可以依赖的版本,构建不会随时间的变化而变化
      6. https://www.youtube.com/watch?v=F8nrpe0XWRg&ab_channel=SingaporeGophers
      7. 不被理解的工作方式
      8. GOPATH
      9. vendor
      10. 三大要点
      11. 兼容性
      12. 可重复性
      13. 合作(通常被很多人忽略)
    4. 默认启用 Go Moduels, go build 必须包含 go.mod 文件,否则编译失败
    5. build/test 不会升级 modules
    6. 默认 -mod=vendor
  2. 文件系统接口

    1. fs.FS 抽象的重要性在哪里

      1. unix file system abstract always disk blocks
      2. network file systems (upspin) abstract away machines
      3. rest abstract nearly anything
      4. cp 不关心是否移动文件的区块,甚至不关心文件在哪个位置,可能是不同的磁盘也可能是不同的机器
      5. 定义任何文件类型工具的「泛型」
    2. 导致了哪些主要变化

      1. io/ioutil
        1. Russ cox 对 deprecated 在 go 中的解释(https://twitter.com/_rsc/status/1351676094664110082)
        2. https://www.srcbeat.com/2021/01/golang-ioutil-deprecated/
      2. 其他 fs 的抽象
      3. Rob Pike 的 2016/2017 Gopherfest, Upspin、Changkun 的 Midgard
        1. https://www.youtube.com/watch?v=ENLWEfi0Tkg&ab_channel=TheGoProgrammingLanguage
        2. FUSE: filesystem in userspace
        3. https://changkun.de/s/midgard
        4. every user has a private root, no global root, r@golang.org/some/stuff, user names look like email address
        5. access control defined by plain text files read: r@golang.org, ann@example.com
      4. 目前的非常简单的实现,只是一个只读文件系统
      5. ReadDir and DirEntry
        1. https://benhoyt.com/writings/go-readdir/
      6. 可扩展的方向:memoryFS,支持回写到磁盘、hashFS 为 CDN 提供支持
      7. 还存在的问题。。例如 44166
      1
      2
      3
      4
      5
      6
      7
      
      import _ "embed"
      //go:embed a.txt
      var s string
      
      import "embed"
      type embed.String string
      var s embed.String
      
      1
      
      
      
  3. 文件嵌入 //go:embed

    1. 新特性的基本功能
    2. 一些可能的应用
    3. 一些在feature freeze cycle 中才讨论出来的feature
    4. https://blog.carlmjohnson.net/post/2021/how-to-use-go-embed/
  4. 运行时内存管理

    1. 回归 MADV_DONTNEED
    • https://blog.changkun.de/posts/pss-uss-rss/
    1. 新的监控基础设施 runtime/metrics
    • 以前的监控函数:runtime.ReadMemStats, debug.GCStats,
    • runtime/metrics:
      • metrics.All()
      • Issue 37112
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package main

import (
	"fmt"
	"runtime/metrics"
)

func main() {
	// Get descriptions for all supported metrics.
	descs := metrics.All()

	// Create a sample for each metric.
	samples := make([]metrics.Sample, len(descs))
	for i := range samples {
		samples[i].Name = descs[i].Name
	}

	// Sample the metrics. Re-use the samples slice if you can!
	metrics.Read(samples)

	// Iterate over all results.
	for _, sample := range samples {
		// Pull out the name and value.
		name, value := sample.Name, sample.Value

		// Handle each sample.
		switch value.Kind() {
		case metrics.KindUint64:
			fmt.Printf("%s: %d\n", name, value.Uint64())
		case metrics.KindFloat64:
			fmt.Printf("%s: %f\n", name, value.Float64())
		case metrics.KindFloat64Histogram:
			// The histogram may be quite large, so let's just pull out
			// a crude estimate for the median for the sake of this example.
			fmt.Printf("%s: %f\n", name, medianBucket(value.Float64Histogram()))
		case metrics.KindBad:
			// This should never happen because all metrics are supported
			// by construction.
			panic("bug in runtime/metrics package!")
		default:
			// This may happen as new metrics get added.
			//
			// The safest thing to do here is to simply log it somewhere
			// as something to look into, but ignore it for now.
			// In the worst case, you might temporarily miss out on a new metric.
			fmt.Printf("%s: unexpected metric Kind: %v\n", name, value.Kind())
		}
	}
}

func medianBucket(h *metrics.Float64Histogram) float64 {
	total := uint64(0)
	for _, count := range h.Counts {
		total += count
	}
	thresh := total / 2
	total = 0
	for i, count := range h.Counts {
		total += count
		if total > thresh {
			return h.Buckets[i]
		}
	}
	panic("should not happen")
}
  1. 其他值得一提的特性
    1. os/signal.NotifyContext
    2. 内存模型修复
    3. 链接器优化

PSS/USS 和 RSS 其实是一回事,吗?

Published at发布于:: 2021-01-23   |   Reading阅读:: 7 min

从 Go 1.12 开始就不断有人踩到监控误报的坑,原因是 Go 从 1.12 开始将 madvise 系统调用 使用的内存回收策略从 MADV_DONTNEED 改为了 MADV_FREE。 从可查的一些文档来看,RSS 作为最常用的内存监控指标,不会反映进程中未被操作系统回收的那部分内存。 自然就会有一些说法建议将 RSS 更换为可能更妥当的指标,比如 PSS 甚至 USS。 这就导致了一些比较 tricky 的问题,PSS 和 USS 并不如 RSS 常用,文档上也没有更多的说明它们 实际能够反应的内存消耗状况,它们真的比 RSS 更合适吗?

Read More阅读更多 »
1 2 3 4 5 6 7 8
© 2008 - 2026 Changkun Ou. All rights reserved.保留所有权利。 | PV/UV: /
0%