最近线上开发C++时,遇到一个性能问题,业务场景简单描述为:
给定m个商品ID, 4个特征(特征数量可增可减),已知商品对应的每个特征的值,如何快速获取某个商品的某个特征值?
当时我采取的是stl嵌套的数据结构,由于时间复杂度较高,且vector的值是随着map的rehash阶段不断进行内存拷贝的, 在全量计算特征的时候会给性能造成很大的压力,当时与base的性能对比如下:
性能不达标,无法上线,经过一番思考,最终采取了如下数据结构:
std::unordered_map<int64_t, float> FeatureKeyV;
std::vector<FeatureKeyV*> FeatureKeyValueVec;
其中,FeatureKeyV负责存储商品ID与特征值的对应关系,FeatureKeyValue每行代表一个特征,负责存储每个商品在该特征上的取值。在获取商品特征值时,首先获取该特征的行数i,得到FeatureKeyValue第i行的FeatureKeyV指针,最后根据商品id即可得到对应的特征值。整个检索过程的时间复杂度仅来源于哈希表的查找,众所周知,哈希表的特点就是查找效率高,时间复杂度为常数级别O(1)。
源码如下:
/**
* 给定m个商品ID, 4个特征(特征数量可增可减),已知商品对应的每个特征的值,如何快速获取某个商品的某个特征值?
*/
#include <iostream>
#include<unordered_map>
enum {
FEATURE_IREM_NUM_1=0,
FEATURE_IREM_NUM_2,
FEATURE_IREM_NUM_3,
FEATURE_IREM_NUM_4,
FEATURE_TOTAL_NUM
};
typedef std::unordered_map<int64_t, float> FeatureKeyV;
typedef std::vector<FeatureKeyV*> FeatureKeyValueVec;
FeatureKeyValueVec features;
static const size_t NUM_DOC_ROW_NUM = 750;
void Init()
{
features.resize(FEATURE_TOTAL_NUM);
for(size_t i = 0; i < features.size(); i++) {
FeatureKeyV* &f = features[i];
f = new FeatureKeyV(NUM_DOC_ROW_NUM);
}
}
void SetFeature(int64_t sku, int fid, float value)
{
if(fid > FEATURE_IREM_NUM_4 or fid < FEATURE_IREM_NUM_1)
return;
int i = fid - FEATURE_IREM_NUM_1;
if(features[i])
(*(features[i]))[sku] = value;
}
int GetFeature(int64_t sku, int fid, float &value)
{
if(fid > FEATURE_IREM_NUM_4 or fid < FEATURE_IREM_NUM_1)
return -1;
int i = fid - FEATURE_IREM_NUM_1;
if(features[i])
{
FeatureKeyV::iterator it = features[i]->find(sku);
if (it == features[i]->end())
return -1;
value = it->second;
return 0;
}
return -1;
}
void Reset()
{
for(size_t i = 0; i < features.size(); i++)
{
if(features[i])
{
features[i]->clear();
delete features[i];
}
}
}
int main()
{
Init();
int64_t sku1 = 10000;
SetFeature(sku1,FEATURE_IREM_NUM_1,20);
SetFeature(sku1,FEATURE_IREM_NUM_2,30);
SetFeature(sku1,FEATURE_IREM_NUM_3,40);
SetFeature(sku1,FEATURE_IREM_NUM_4,50);
int64_t sku2 = 10001;
SetFeature(sku2,FEATURE_IREM_NUM_1,22);
SetFeature(sku2,FEATURE_IREM_NUM_2,33);
SetFeature(sku2,FEATURE_IREM_NUM_3,44);
SetFeature(sku2,FEATURE_IREM_NUM_4,55);
float value;
if (!GetFeature(sku2, FEATURE_IREM_NUM_1, value))
{
cout << "feature:" << value << endl;
}
Reset();
}
优化后的性能对比如下:
性能达到上线标准,可见学好数据结构的重要性,有人曾经说过,一个优秀的算法,往往是利用最简单的数据结构解决最复杂的问题,如果数据结构设计比较复杂,那么一定是设计不合理。