auto-cfs-cores C++ 版 automaxprocs
之前写了一篇分析 uber 的 automaxprocs 的源码,后面抽个了时间写了一个 C++ 版本的。
其一是为了加深对原库的理解;其二是避免太长时间没写 C++ 手生,以及顺带体验一下 C++ 17 的感觉。
代码在:https://github.com/kingsamchen/Eureka/tree/master/auto-cfs-cores
之前写了一篇分析 uber 的 automaxprocs 的源码,后面抽个了时间写了一个 C++ 版本的。
其一是为了加深对原库的理解;其二是避免太长时间没写 C++ 手生,以及顺带体验一下 C++ 17 的感觉。
代码在:https://github.com/kingsamchen/Eureka/tree/master/auto-cfs-cores
最近直播内部的 golang 服务都使用了 uber 出品的 automaxprocs 这个库。
据伟大的 @ice 马总说,这个库解决了一个困扰B站整个golang(container)技术栈一年多的问题。
出于好奇这个库到底做了什么 magic,能够解决这个持续了一年多的 pain in the ass,抽了一点时间,稍微翻了一下库的源代码,记录如下。
线上容器里的服务通常都对 CPU 资源做了限制,例如默认的 4C。
但是在容器里通过 lscpu
仍然能看到宿主机的所有 CPU 核心:
1 | rchitecture: x86_64 |
这就导致 golang 服务默认会拿宿主机的 CPU 核心数来调用 runtime.GOMAXPROCS()
,导致 P 数量远远大于可用的 CPU 核心,引起频繁上下文切换,影响高负载情况下的服务性能。
本文是对 Jeff Preshing 的 Double Checked Locking Is Fixed in C++ 11 笔记。
因为 synchronization 只需要在实例第一次创建时保证;此后( instance != nullptr
时)都不需要锁来保证 synchronization。
在第一次判断实例为空和上锁之间存在一个 potential race,因此上锁后需要再一次判断实例是否为空。
这也是 double checked 的来由。
所以一个传统但并不100%正确的 DCLP 实现如下:
1 | class Singleton { |
这基本是早起 C++ DCLP 的实现架子。
语句
1 | instance = new Singleton(); |
在 C++ 中实际上等效于
1 | tmp = operator new(sizeof(Singleton)); // step 1: allocate memory via operator new |
注意:其中除了分配内存是固定第一步之外,构造对象和赋值内存地址的生成代码顺序是由编译器自己决定。这里的顺序只是一种可能性。
近段有相当一部分时间在熟悉和练习 ASIO。
练习过程中发现 ASIO 中如何使用&管理 buffer 是新手大概率会遇到的问题。
结合最近几个 practice demo,稍微简单总结了一下使用经验:
0x00
const_buffer
和 mutable_buffer
是两个 fundamental buffer classes。二者的区别在语义上表达的很明显了。
实现上二者提供的接口非常一致,除了一个面向 const void*
,另一个面向 void*
。这点可以从 ctor 和 data()
中看出。
另外,为了和 C++ 现有的 const cast semantics 保持一致,一个 mutable_buffer
对象可以 implicitly converted to const_buffer
。
首先承认这个标题乍看之下很像 troll,但真的不是 troll;“避免使用”总的来说更接近 whenever possible 的意思。
另外,这篇 post 面向的主要是偏底层的、直接使用 system calls 或其 runtime wrapper(glibc)的开发者,最典型的比如 C/C++ 开发者。
其他语言的开发者通常因为要么 runtime “屏蔽”了这部分内容(如 Java);要么 runtime 自身对这部分做了较大的抽象/改造(如 Golang),因此很难对此 post 提到的各种观点/做法产生共鸣。
FYI:自从工作后中文写作能力一直在退化,因此这篇文章如果存在语句不通顺或者用词不当的地方,烦请见谅。
signal 源自 Unix,后来成为 POSIX 标准的一部分,现在则被几乎所有的 *nix 系统支持。
signal 本质上是一种通讯机制,用于系统在某个事件(event)发生时通知某个进程(或线程)。