Rom*_*man 7 c++ multithreading c++11
下面的代码演示了多线程编程的好奇心.特别std::memory_order_relaxed是单个线程中增量与常规增量的性能.我不明白为什么fetch_add(宽松)单线程比常规增量慢两倍.
static void BM_IncrementCounterLocal(benchmark::State& state) {
volatile std::atomic_int val2;
while (state.KeepRunning()) {
for (int i = 0; i < 10; ++i) {
DoNotOptimize(val2.fetch_add(1, std::memory_order_relaxed));
}
}
}
BENCHMARK(BM_IncrementCounterLocal)->ThreadRange(1, 8);
static void BM_IncrementCounterLocalInt(benchmark::State& state) {
volatile int val3 = 0;
while (state.KeepRunning()) {
for (int i = 0; i < 10; ++i) {
DoNotOptimize(++val3);
}
}
}
BENCHMARK(BM_IncrementCounterLocalInt)->ThreadRange(1, 8);
Run Code Online (Sandbox Code Playgroud)
输出:
Benchmark Time(ns) CPU(ns) Iterations
----------------------------------------------------------------------
BM_IncrementCounterLocal/threads:1 59 60 11402509
BM_IncrementCounterLocal/threads:2 30 61 11284498
BM_IncrementCounterLocal/threads:4 19 62 11373100
BM_IncrementCounterLocal/threads:8 17 62 10491608
BM_IncrementCounterLocalInt/threads:1 31 31 22592452
BM_IncrementCounterLocalInt/threads:2 15 31 22170842
BM_IncrementCounterLocalInt/threads:4 8 31 22214640
BM_IncrementCounterLocalInt/threads:8 9 31 21889704
本地版本不使用原子。(它使用的事实volatile是一个转移注意力的事实 -volatile在多线程代码中基本上没有任何意义)。
原子版本使用原子(!)。实际上只有一个线程将用于访问该变量,这一事实对 CPU 来说是不可见的,而且我对编译器没有发现它也并不感到惊讶。(没有必要浪费开发人员的精力来确定转换为 是否安全std::atomic_int,int而实际上它几乎永远不会安全。atomic_int如果不需要从多个线程访问它,没有人会编写。)
因此,原子版本会遇到麻烦,要确保增量实际上是原子的,坦率地说,我很惊讶它只慢了 2 倍 - 我本来预计会慢 10 倍。