C++ 如何在C++;关于CPU和内存
我正在迭代一个映射,需要根据未找到元素的条件(可能是任何其他条件)在该映射上添加元素 我的主要问题是,由于要添加大量更新,应用程序占用了整个CPU和所有内存 国家级:C++ 如何在C++;关于CPU和内存,c++,c++11,unordered-map,C++,C++11,Unordered Map,我正在迭代一个映射,需要根据未找到元素的条件(可能是任何其他条件)在该映射上添加元素 我的主要问题是,由于要添加大量更新,应用程序占用了整个CPU和所有内存 国家级: class State { int id; int timeStamp; int state; } 状态中的方法: void State::updateStateIfTimeStampIsHigher(const State& state) { if (this->id ==
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));
}
}
}
std::地图数据;
const std::映射和更新;
用于(自动常量和更新:更新){
if(updatePos.first!=this->toNodeId){
std::map::iterator message=data.find(updatePos.first);
if(message!=data.end()&&message->first){
message->second.updateStateIfTimeStampIsHigher(updatePos.second);
}否则{
data.insert(std::make_pair(updatePos.first,updatePos.second));
}
}
}
查看KCacheGrind数据看起来像data.insert()行占用了大部分时间/内存。我是KCacheGrind的新手,但这条线似乎占到了成本的72%左右
你对如何改进这一点有什么建议吗?你的问题很笼统,但我认为有一些方法可以让它运行得更快:
emplace\u 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);
}
}
std::地图数据;
const std::地图更新;
自动最近=data.begin();
用于(自动常量和更新:更新){
如果(UpdateLemNotFound){
最近=数据。安放提示(最近,更新);
}
}
另外,如果你想用CPU来交换内存,你可以使用无序的映射(),但第一个点不再重要。通过研究对这个问题的评论,我可以找到一个满意的答案。从地图改为无序地图确实有点帮助,但我还是得到了不满意的结果 我最终使用了谷歌的,它提供了更好的资源利用率,尽管删除条目有一些缺点(我确实这么做) 代码解决方案如下所示。首先,我包括所需的库:
#include <sparsehash/sparse_hash_map>
最后,我的循环代码变化很小:
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 0m37,464s
user 0m37,032s
sys 0m0,428s
我将其与其他案例和类似结果(从定性角度)一起运行。系统时间和资源使用(CPU和内存)减少,用户时间增加
总的来说,我对这个折衷方案感到满意,因为我更关心的是资源使用情况而不是执行时间(应用程序是一个模拟器,它无法在非常重的负载下完成并获得结果,现在它可以了)。您考虑过
数据吗?您应该阅读以下内容:1)Francois的建议2)如何更改数据和算法?例如,您是否需要int
作为键?什么是状态
?它是否足够小,以至于复制构造函数速度很快,或者可以将其更改为小?int
键是否足够密集,可以使用std::vector
而不使用键,并且在未使用的索引处有空白?等等,等等…由于两个贴图具有相同的结构,您可以使用暗示插入,因为您保证在末尾插入。这不会节省分配,而是节省搜索时间。update
map是否必须保持不变?如果您可以将其分解,则可以节省重新分配的费用。您的算法具有n log n
复杂性,而它可以使用与合并算法等效的线性时间来完成。使用emplace_提示并不能提供更好的性能,但将映射更改为无序映射会产生一些性能增益。我仍然需要努力改进。这个解决方案的缺点是我无法使它在Windows上工作。它在Linux上工作。
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