static_assert(sizeof(uintptr_t) == 8, \"Only works on 64-bit systems\");
template <typename T>
uintptr_t MarkDirty(T* t) {
return reinterpret_cast<uintptr_t>(t) | kDirtyBit;
}
template <typename T>
T* GetPointer(uintptr_t t) {
return reinterpret_cast<T*>(t & kPtrMask);
}不过,有趣的是,由于这是Linux内存管理/虚拟地址空间的一个特性,所以它可能会发生变化,而且实际上已经发生了变化!
LWN(Linux Weekly News)在2017年发布了补丁集,实现了五级页表,以支持更大数量的可寻址内存空间 。如果启用这个更改的话,Linux的虚拟内存寻址空间将从现在48位提高到57位,从而将虚拟内存寻址空间的大小从256 TiB增加到128 PiB,这对于每个人来说都足够了 。
默认情况下这个更改无法启用 。部分原因是各种高性能程序,特别是各种JavaScript引擎和 LuaJIT,对寻址空间高位用途的调整会导致一些额外的数据被打包到指针中 。
锁定条带化(Lock Striping)
当你希望多个线程以独占方式访问共享数据时,锁可以用于互斥 。但缺点是 , 如果共享数据被频繁访问,而且这是系统的关键部分的话 , 那么线程可能会将大部分时间花在锁的争用上,而不是实际工作上 。
解决这个问题的一个常见方法是引入更多的锁 。你说什么?等一下!
好吧 , 我想说的是:不是一个保护所有数据的锁,而是有许多只负责一部分数据的锁 。通过这种方式 , 我们将数据分成独立的、互不竞争的存储桶 。假设数据访问方式都倾向于一致的,增加数据的切分会按比例减少争用锁的线程数 。
下面是用C++写的一个小例子 , 提供了线程安全的hash-set的两种实现 。第一个实现ThreadSafeHashSet使用单个锁来保护单个基础hash-set(absl::flat_hash_set) 。第二个实现LockStripedHashSet有N个单独的锁,保护N个单独的基础hash-set(abs::flat_hash_sets) 。
// Simple thread-safe single-lock hash set为了说明锁定条带化的好处,我们在多个线程存在的情况下对两个线程安全的hash-set性能进行了基准测试,每个线程都插入了一百万项 。对于LockStripedHashSet , 我们尝试将数据拆分成4块和8块 。结果如下:
class ThreadSafeHashSet {
public:
void Insert(uint64 i) {
absl::MutexLock lock(&mu_);
hash_set_.insert(i);
}
bool Contains(uint64 i) {
absl::MutexLock lock(&mu_);
return hash_set_.contains(i);
}
private:
absl::Mutex mu_;
absl::flat_hash_set<uint64> hash_set_;
};
// Chunk the data into `kNumChunks` separate hash sets, guarded by separate
// locks.
template <size_t kNumChunks>
class LockStripedHashSet {
public:
void Insert(uint64 i) {
// Mod the data to calculate which hash_set/lock to use
const size_t idx = i % kNumChunks;
absl::MutexLock lock(&mu_[idx]);
hash_set_[idx].insert(i);
}
bool Contains(uint64 i) {
const size_t idx = i % kNumChunks;
absl::MutexLock lock(&mu_[idx]);
return hash_set_[idx].contains(i);
}
private:
std::array<absl::Mutex, kNumChunks> mu_;
std::array<absl::flat_hash_set<uint64>, kNumChunks> hash_set_;
};
Executing tests from //examples:lock-striping
-----------------------------------------------------------------------------
2019-08-24 22:24:37
Run on (4 X 2800 MHz CPU s)
CPU Caches:
L1 Data 32K (x2)
L1 Instruction 32K (x2)
L2 Unified 262K (x2)
L3 Unified 4194K (x1)
--------------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------------
BM_SingleLock/threads:1 65 ms 65 ms 11
BM_SingleLock/threads:2 140 ms 254 ms 2
相关经验推荐
- 分公司需要营业执照吗
- 葡萄苗6月份能栽活吗视频 葡萄苗6月份能栽活吗
- 兔子要养多久才会生
- 上肉桂是什么东西
- 自制万能花肥营养液 自制万能花肥
- 卡西欧小方块怎么调表带
- 浙江新昌房价 浙江新昌
- 凡尔赛是什么意思
- 金诺三髓粉
- 春天开什么花的名字和图片 春天开什么花的名字
