多線程協作免不了使用計數器,
通常的代碼,c++一般會使用鎖,或者原子變量操作:
std::mutex mutexCounter;
int count;
void add()
{
std::lock_guard<std::mutex> guard(mutexCounter);
count ++;
}
std::atomic<int> count;
void add()
{
count ++;
}
在性能要求比較高的情況下,這樣的代碼100%是整個業務的瓶頸;
那麼如何優化?答案是讓線程寫到自己的計數内,在計算總和時候再使用鎖來彙總一次;
方法一:
可以每個線程配置設定一個0-N (64個左右)的索引号,通過索引去通路計數單元中的對應的的槽位,這樣線程之間不會互相影響,就實作了無鎖寫入;讀的時候可以根據對精度的要求來确定是否需要加鎖同步統計:
#pragma once
#include <thread>
#include <mutex>
#include <map>
#include <vector>
class VarBase
{
public:
static int getIndex();
private:
static int cusor;
static thread_local int index;
//static std::map<std::thread::id, int> idMap;
static std::mutex mutexMap;
};
class VarSingle
{
public:
VarSingle() : data(64)
{
}
inline int setData(int val)
{
int index = VarBase::getIndex();
if (index >= data.size())
{
std::lock_guard<std::mutex> gurad(mutexVec);
if (index >= data.size())
data.resize(data.size() + 16);
}
data[index] = val;
return index;
}
int getVal()
{
int index = VarBase::getIndex();
if (index >= data.size())
return 0;
return data[index];
}
int64_t getSum(bool precise)
{
int64_t all = 0;
if (precise)
{
std::lock_guard<std::mutex> gurad(mutexVec);
for (size_t i = 0; i < data.size(); i++)
{
all += data[i];
}
}
else
{
for (size_t i = 0; i < data.size(); i++)
{
all += data[i];
}
}
return all;
}
void reset()
{
std::lock_guard<std::mutex> gurad(mutexVec);
for (size_t i = 0; i < data.size(); i++)
{
data[i] = 0;
}
}
private:
std::vector<int> data;
std::mutex mutexVec;
};
// Var.cpp
#include "Var.h"
int VarBase::index = -1;
int VarBase::cusor = 0;
int VarBase::getIndex()
{
if (index == -1)
{
std::lock_guard<std::mutex> guard(mutexMap);
index = cusor++;
}
return index;
}
第二種:
可以設定全局的一個map資訊,
Var的構造函數,将自己的線程局部存儲的指針注冊到全局資訊中,在析構時候删除注冊資訊;
這樣,每次寫資料都寫到線程本地存儲中,而統計時候通過全局注冊資訊彙總;
代碼,略;