【发布时间】:2018-10-23 19:49:31
【问题描述】:
我正在对一些练习和一个特定程序进行评分,尽管算法似乎正确,但它太慢了(我的意思是 太 慢)。该程序正在使用map::at(在 C++11 中引入)访问地图。只需将at 替换为find(并修复语法),同样的程序会非常快(与原始版本相比)。
查看 cplusplus.com 两种方法都声称具有相同的复杂性,但我不明白为什么其中一种会有所不同(除了 API 原因、不引发异常等)。
然后我看到关于数据竞争的部分中的描述有所不同。但我并不完全理解其中的含义。我的假设是否 map::at 是线程安全的(而 map::find 不是)并因此导致一些运行时惩罚正确吗?
http://www.cplusplus.com/reference/map/map/at/
http://www.cplusplus.com/reference/map/map/find/
编辑
两者都在一个称为 10.000.000 次的循环中。没有优化标志。只需g++ foo.cpp。这是差异(arrayX 是向量,m 是地图)
< auto t = m.find(array1.at(i));
< auto t2 = t->second.find(array2.at(i));
< y = t->second.size();
< cout << array.at(i) << "[" << t2->second << " of " << y << "]" << endl;
---
> auto t = m.at(array1.at(i));
> x = t.at(array2.at(i));
> y = m.at(array1.at(i)).size();
> cout << array.at(i) << "[" << x << " of " << y << "]" << endl;
【问题讨论】:
-
“除了 API 原因,不抛出异常等” - 这会影响性能。特别是如果它是算法的关键部分。线程安全版本也慢了一点
-
我在两个版本中都没有出现任何异常。所以没有“活动”异常处理发生,没有堆栈展开等。
-
您误解了异常的处理。考虑
std::vectorsoperator[]和at函数。他们俩的速度都是O(1)。它们都使您可以访问nth 元素。但是,如果您提供了不正确的索引,operator[]的行为是未定义的。可能它会给你一个垃圾参考。at,另一方面,每次调用它时,它执行检查 - 简单的if语句来查看索引是否超出范围。如果是,则抛出异常。如果没有抛出异常并且索引有效,则您“失去”一些时间来执行检查 -
您的映射类型是什么?我很确定对于您的代码中的
auto t,推断出mapped_type(而不是参考),这会导致mapped_type副本。试试auto& t。 -
哇!那是罪魁祸首。将
auto t更改为auto& t并保持map::at它运行得非常快!
标签: c++11 thread-safety stdmap