这个设计有没有可以改进的地方?

lorinsz
lorin 09月12日 字数 1564

请教各位cpp大牛,这个设计有啥可以改进的地方,让代码看上去简洁优雅一些。

有一个struct,定义了一堆各种数据类型(int,float,double, array, array<vector>, array<vector<vector>>)的metric,主要是log一个系统的各种performance metric,系统很大很复杂,大概有几百个变量

struct Metrics {

float latency1;    // 几百个这样的变量

double latency2;

...

};

Metrics类有一个更新其中部分数据的api(每隔几秒会拿到一部分metric的更新值,目前从其他地方传过来是存在一个map里,用的是string->variant): updateMetricsValue(const std::unordered_map<std::string, std::variant>& sample),map一般每次有十几个变量。大部分metric更新是直接赋值,有些需要进行一些简单计算,比如map里存的是一个vector,metric其实要的是平均或者中位数。

现在我的做法是在Metrics类里搞了一个lambda map用来定义metric的更新函数,对于每一个metric变量写一个lambda,这个map放在了Metrics类里。

struct Metrics {

std::unordered_map<std::string, std::function<void(const std::unordered_map<std::string, std::variant> &sample)>> fxmap;

void makeFxmap() {

fxmap["latency_1"] = [&latency1](const std::unordered_map<std::string, std::variant> &sample) {

latency1 = std::get<float>(sample.at("latency_1"));

};

// 每一个metric的更新方式都要定义一个lambda。

// ....

}

};

这样写的原因是让updateMetricsValue(sample)比较简洁:

updateMetricsValue(const std::unordered_map<std::string, std::variant>& sample) {

for (auto& [key, data] : sample) {

fxmap[key](sample);

}

}

现在的问题是makeFxmap()这个创建lambda map的函数巨长无比,reflection的模式能用在这里吗?(据我所知C++20还没有)。有没有办法搞个模版函数可以让代码简洁?谢谢!

6 个回复
bihai
new half life 09月13日

也许我那个建议有点用,就是用数组和enum

enum IntLatencies {

iLATENCY1,

iLATENCY2,...

iEND

};

enum DoubleLatencies {

dLATENCY1,

dLATENCY2,...

dEND

};

struct Metrics {

float ilatencies[iEND];

double ...

};

这样

void makeFxmap() {

for(i ...) {

fxmap[tostring("latency_")+i] = ...

}

// 每一种类型写一个即可

}

【 在 lorinsz 的大作中提到: 】

: 请教各位cpp大牛,这个设计有啥可以改进的地方,让代码看上去简洁优雅一些。

: 有一个struct,定义了一堆各种数据类型(int,float,double, array, array<vector>, array<vector<vector>>)的metric,主要是log一个系统的各种performance metric,系统很大很复杂,大概有几百个变量

: struct Metrics {

: ...................

foliver
Oliver 09月13日
foliver
Oliver 09月13日

度量值也应该用value map的方式保存,而不是单独搞几百个变量。

这样即节省代码, 也利于序列化,以后扩展。

【 在 lorinsz 的大作中提到: 】

: 请教各位cpp大牛,这个设计有啥可以改进的地方,让代码看上去简洁优雅一些。

: 有一个struct,定义了一堆各种数据类型(int,float,double, array, array<vector>, array<vector<vector>>)的metric,主要是log一个系统的各种performance metric,系统很大很复杂,大概有几百个变量

: ...................

StephenLee
薛定谔的猫 09月13日

直接安装 prometheus 它不香么

【 在 lorinsz 的大作中提到: 】

: 请教各位cpp大牛,这个设计有啥可以改进的地方,让代码看上去简洁优雅一些。

: 有一个struct,定义了一堆各种数据类型(int,float,double, array, array<vector>, array<vector<vector>>)的metric,主要是log一个系统的各种performance metric,系统很大很复杂,大概有几百个变量

: ....................

leslin
我心有约 09月13日

这种体力活,我的意见一直是,其实怎么做都差不多,只要做好封装,别影响到其他部分就好。。。

如果写着写着,发现确实有很多重复代码再迭代也不迟

【 在 lorinsz 的大作中提到: 】

: 请教各位cpp大牛,这个设计有啥可以改进的地方,让代码看上去简洁优雅一些。

: 有一个struct,定义了一堆各种数据类型(int,float,double, array, array<vector>, array<vector<vector>>)的metric,主要是log一个系统的各种performance metric,系统很大很复杂,大概有几百个变量

: struct Metrics {

: ...................

lorinsz
lorin 09月13日

嗯 对的 准备用hashmap替代先

发自「今日水木 on iPhone XS」

【 在 foliver 的大作中提到: 】

: 度量值也应该用value map的方式保存,而不是单独搞几百个变量。

: 这样即节省代码, 也利于序列化,以后扩展。

: --

here080
hero080 09月24日

void Makemap() {

SetFunctor(&latency1, "latency1");

SetFunctor(&latency2, "latency2");

SetFunctor(&some_variable, "some_key");

...

}

SetFunctor()的实现你会的。

【 在 lorinsz (lorin) 的大作中提到: 】

: 标  题: 这个设计有没有可以改进的地方?

: 发信站: 水木社区 (Sun Sep 12 18:26:55 2021), 站内

: 请教各位cpp大牛,这个设计有啥可以改进的地方,让代码看上去简洁优雅一些。

: 有一个struct,定义了一堆各种数据类型(int,float,double, array, array<vector>, array<vector<vector>>)的metric,主要是log一个系统的各种performance metric,系统很大很复杂,大概有几百个变量

: struct Metrics {

:   float latency1;    // 几百个这样的变量

:   double latency2;

:   ...

: };

: Metrics类有一个更新其中部分数据的api(每隔几秒会拿到一部分metric的更新值,目前从其他地方传过来是存在一个map里,用的是string->variant): updateMetricsValue(const std::unordered_map<std::string, std::variant>& sample),map一般每次有十几个变量。大部分metric更新是直接赋值,有些需要进行一些简单计算,比如map里存的是一个vector,metric其实要的是平均或者中位数。

: 现在我的做法是在Metrics类里搞了一个lambda map用来定义metric的更新函数,对于每一个metric变量写一个lambda,这个map放在了Metrics类里。

: struct Metrics {

:   std::unordered_map<std::string, std::function<void(const std::unordered_map<std::string, std::variant> &sample)>> fxmap;

:   void makeFxmap() {

:     fxmap["latency_1"] = [&latency1](const std::unordered_map<std::string, std::variant> &sample) {

:       latency1 = std::get<float>(sample.at("latency_1"));

:     };

:     // 每一个metric的更新方式都要定义一个lambda。

:    // ....

:   }

: };

: 这样写的原因是让updateMetricsValue(sample)比较简洁:

: updateMetricsValue(const std::unordered_map<std::string, std::variant>& sample) {

:   for (auto& [key, data] : sample) {

:     fxmap[key](sample);

:   }

: }

: 现在的问题是makeFxmap()这个创建lambda map的函数巨长无比,reflection的模式能用在这里吗?(据我所知C++20还没有)。有没有办法搞个模版函数可以让代码简洁?谢谢!

: --