哈希游戏- 哈希游戏平台- 哈希游戏官方网站在多线程环境中,多个线程同时尝试获取同一个锁(Lock)时,会发生竞争现象,这就是所谓的锁竞争(Lock Contention)。锁竞争会导致线程或进程被阻塞,等待锁被释放,从而影响系统的性能和响应时间。大多数情况下,开发人员会选择使用锁来解决线程间的同步问题,因此锁竞争问题也变得广为人知且容易理解。由于锁的存在,位于临界区的代码在同一时刻只能由一个线程执行。因此,优化的思路就是尽量避免多个线程同时访问同一资源。常见的优化方向有两种:
讲到这里,其实就可以解释为什么开头那段代码会随着线程数量的增加而性能反而下降。代码中的变量 s 是一个共享资源,但它使用了 shared_ptr。在复制 shared_ptr 时,会引起引用计数的增加(计数+1),多个线程频繁对同一个缓存行进行读写操作,从而引发缓存乒乓效应,导致性能下降。最简单的修改方式就是去掉 shared_ptr,代码如下,同时还可以得到我们预期的结果,即CPU时间随着线程数的增加而降低:
#include #include #include #include #include #include constexpr int kSetSize = 10000; struct alignas( 64) PaddedCounter { std::atomic value{ 0}; char padding[ 64 - sizeof(std::atomic )]; // 填充到缓存行大小nt(i) 0) { benchmark::DoNotOptimize(GetSums()[state.thread_index()].value++); } } } } // 注册基准测试,并指定线程数 BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWork)-Threads( 1); BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWork)-Threads( 2); BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWork)-Threads( 4); BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWork)-Threads( 8); BENCHMARK_MAIN();
再来看写操作,写操作除了上锁以外还需要修改节点的数据。第二个方法需要先构造一个新的节点再修改,意味着这个节点在插入链表之前一定不在其他线程的 Cache 里(排除刚好有某个变量和这个新节点的内存在同一个 Cache Line 的情况)。而第一个方法修改的节点已经在链表里,这表示在之前一定有线程已经访问过这个节点,那么它很可能在 Cache 里面,从而触发一次 Cache Line 一致性同步的问题。