gpt4 book ai didi

c++ - 循环内切换的性能

转载 作者:太空宇宙 更新时间:2023-11-04 12:48:30 25 4
gpt4 key购买 nike

我们有一个消息类型到消息列表的映射。给定一段性能关键代码,例如:

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;
}
}

但现在我们有多个冗余的内部循环,“LARGE CODE CHUNK”代码需要重复多次。

我的问题:现代编译器(特别是 g++)能否将版本 1 优化为与版本 2 一样高效?

或者我应该使用版本 2,也许考虑使用一些其他方法来消除冗余,例如在 switch 语句中将函数指针设置为 add_{0/1}_to_database 然后使用该函数循环中的指针?

最佳答案

大概是你真正的row_t比问题中显示的更复杂。如果不是,则无需遍历 vector 。只需使用长度即可。

与性能问题一样,首先要做的是测试。如果您的代码库的这一部分不是性能关键型的,则无需担心。让你的代码简洁明了。这个答案的其余部分假设测试表明这确实是一个性能瓶颈。在找到解决方案之前,我将首先解决两个可能是更大性能问题的项目。

  1. 使用 std::map .遍历有序 map 可能会很昂贵。考虑切换到 std::unordered_map ,这是在 c++11 中引入的。您使用基于范围的循环表明您使用的是 c++11 或更高版本。

  2. 过度复制。外环for (auto x : message_map)制作拷贝,vector<row_t> message_rows = x.second 也是如此和 for (row_t row : message_rows) .您正在复制 vector 两次,再加上每个元素的额外拷贝。使用引用资料。

解决方案:考虑使用函数指针。一种简单的方法是将 switch 语句移出内部循环,而不是像问题中指示的那样有一个循环,而是设置一个函数指针:

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);
}
}

那个 switch 语句有点难看。 2.0 版将其转换为另一张 map :

typedef void (*AddFunction)(const row_t&);
std::unordered_map<int, AddFunction> add_function_map;

// Outside the loop, populate the map:
add_function_map[0] = add_0_to_database;
add_function_map[1] = add_1_to_database;
// Rest of add_function_map population elided.

// The loop is now short and sweet.
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!
AddFunction add_to_database = add_function_map[message_type];
for (row_t& row : message_rows) // Avoid copying!
{
// LARGE CODE CHUNK
add_to_database (row);
}
}

关于c++ - 循环内切换的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50203315/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com