我正在迭代一个地图,我需要在该地图上添加元素,具体取决于未找到元素的条件(可能是任何其他条件)。
我的主要问题是,要添加大量更新,应用程序将占用整个CPU和所有内存。
州级:
class State {
int id;
int timeStamp;
int state;
}
状态方法:
void State::updateStateIfTimeStampIsHigher(const State& state) {
if (this->id == state.getId() && state.getTimeStamp() > this->getTimeStamp()) {
this->timeStamp = state.getTimeStamp();
this->state = state.getState();
}
}
循环代码:
std::map<int, State> data;
const std::map<int, State>& update;
for (auto const& updatePos : update) {
if (updatePos.first != this->toNodeId) {
std::map<int, State>::iterator message = data.find(updatePos.first);
if (message != data.end() && message->first) {
message->second.updateStateIfTimeStampIsHigher(updatePos.second);
} else {
data.insert(std::make_pair(updatePos.first, updatePos.second));
}
}
}
观察KCacheGrind数据看起来像 data.insert()行需要大部分时间/内存。我是KCacheGrind的新手,但这条线似乎约占成本的72%。
您对如何改善这一点有什么建议吗?
答案 0 :(得分:1)
你的问题非常笼统,但我看到了让它运行得更快的事情:
emplace_hint
加快插入速度示例代码:
std::map<int, long> data;
const std::map<int, long> update;
auto recent = data.begin();
for (auto const& updatePos : update) {
if (updateElemNotFound) {
recent = data.emplace_hint(recent, updatePos);
}
}
另外,如果你想用内存交换CPU,可以使用unordered_map(Is there any advantage of using map over unordered_map in case of trivial keys?),但第一个点不再重要了。
答案 1 :(得分:0)
通过研究对问题的评论,我能找到一个令人满意的答案。它确实有助于从 map 更改为 unordered_map ,但我仍然得到了令人不满意的结果。
我最终使用Google的sparsehash提供了更好的资源使用,尽管擦除条目存在一些缺点(我这样做)。
代码解决方案如下。首先,我包括所需的库:
#include <sparsehash/sparse_hash_map>
然后,我的新数据定义如下:
struct eqint {
bool operator()(int i1, int i2) const {
return i1 == i2;
}
};
google::sparse_hash_map<int, State, std::tr1::hash<int>, eqint> data;
由于我必须使用“擦除”,所以我必须在 sparsemap 构造之后执行此操作:
data.clear_deleted_key();
data.set_deleted_key(-1);
最后我的循环代码变化很小:
for (auto const& updatePos : update) {
if (updatePos.first != this->toNodeId) {
google::sparse_hash_map<int, State, std::tr1::hash<int>, eqint>::iterator msgIt = data.find(updatePos.first);
if (msgIt != data.end() && msgIt->first) {
msgIt->second.updateStateIfTimeStampIsHigher(updatePos.second);
} else {
data[updatePos.first] = updatePos.second;
}
}
}
之前在特定参数下运行整个应用程序的更改的时间是:
real 0m28,592s
user 0m27,912s
sys 0m0,676s
在相同的特定参数下运行整个应用程序的更改之后的时间是:
real 0m37,464s
user 0m37,032s
sys 0m0,428s
我用其他案例运行它,结果类似(从定性的角度来看)。系统时间和资源使用(CPU和内存)减少,用户时间增加。
总体而言,我对这种权衡感到满意,因为我更关注资源使用而不是执行时间(应用程序是一个模拟器,它无法完成并在非常重的负载下获得结果,现在确实如此)。