我们有一个消息类型映射到消息列表。给出一个性能关键的代码,例如:
struct row_t {
int message_type; //0,1,2,3,4,5
};
map<int, vector<row_t>> message_map;
for (auto x : message_map) {
int message_type = x.first;
vector<row_t> message_rows = x.second;
for (row_t row : message_rows) {
//LARGE CODE CHUNK
switch(row.message_type) { //same as switch(message_type)
case 0:
add_0_to_database();
break;
case 1:
add_0_to_database();
break;
//...
default:
break;
}
}
}
switch语句将在内部循环的每次迭代中执行,即使message_rows中的每个元素都具有相同的类型。
这个问题可以消除,只在内循环开始之前运行一次switch语句:
for (auto x : message_map) {
int message_type = x.first;
vector<row_t> message_rows = x.second;
switch(message_type) {
case 0:
for (row_t row : message_rows) {
//LARGE CODE CHUNK
add_0_to_database(row);
}
break;
case 1:
for (row_t row : message_rows) {
//LARGE CODE CHUNK
add_1_to_database(row);
}
break;
//...
default:
break;
}
}
但是现在我们有多个冗余的内部循环和#34; LARGE CODE CHUNK&#34;代码需要多次重复。
我的问题:现代编译器(特别是g ++)可以优化版本1以与版本2一样高效吗?
或者我应该使用版本2,也许可以考虑使用其他方法来删除冗余,例如在switch语句中将函数指针设置为add_{0/1}_to_database
,然后在循环中使用函数指针?
答案 0 :(得分:0)
据推测,您的真实row_t
比问题中显示的要复杂得多。如果不是,则无需循环向量。只需使用长度。
与性能问题一样,首先要做的是测试。如果您的代码库的这部分不是性能关键的话,则无需担心。使您的代码干净简单。这个答案的其余部分假设测试表明这确实是一个性能瓶颈。在我找到解决方案之前,我将首先解决两个可能是更大的性能问题的项目。
使用std::map
。遍历有序地图可能很昂贵。考虑切换到{+ 1}},这是在c ++ 11中引入的。使用基于范围的循环表示您使用的是c ++ 11或更高版本。
过度复制。外部循环std::unordered_map
制作副本,for (auto x : message_map)
和vector<row_t> message_rows = x.second
也是如此。您正在复制矢量两次,以及每个元素的附加副本。使用参考文献。
解决方案:考虑使用函数指针。一个简单的方法是将switch语句移出内部循环,但不是像问题中所示的循环,而是设置一个函数指针:
for (row_t row : message_rows)
那个switch语句有点难看。 2.0版将其转换为另一个地图:
for (auto& x : message_map) // Note the use of auto& to avoid copying.
{
int message_type = x.first;
std::vector<row_t>& message_rows = x.second; // Avoid copying!
void (* add_to_database)(const row_t&) = nullptr;
switch(message_type)
{
case 0:
add_to_database = add_0_to_database;
break;
case 1:
add_to_database = add_1_to_database;
break;
//...
default:
// This might be an error that should be handled here.
break;
}
for (row_t& row : message_rows) // Avoid copying!
{
// LARGE CODE CHUNK
add_to_database (row);
}
}