3

我记得我在某个地方(可能在 Github 中)在 setter 中看到过这样的示例:

void MyClass::setValue(int newValue)
{
    if (value != newValue) {
        value = newValue;
    }
}

对我来说这没有多大意义,但我想知道它是否能提高性能。

4

4 回答 4

7

它对 没有意义scalar types,但对某些user-defined类型可能有意义(因为类型可能真的很“大”,或者它的赋值运算符可以做一些“艰苦”的工作)。

于 2013-05-09T21:32:37.130 回答
4

您真正能分辨的唯一方法是实际测试不同的替代方案(基准测试和/或分析代码)。不同的编译器、不同的处理器和不同的代码调用它会产生很大的不同。

一般来说,对于“简单”数据类型(int、double、char、指针等),它没有意义。它只会使处理器的代码更长,更复杂[至少如果编译器按照你的要求做 - 它可能会意识到“这没有任何意义,让我们删除这个检查 - 我不会依赖tho' - 编译器通常比你更聪明,但是让编译器的生活变得更加困难几乎永远不会导致更好的代码]。

编辑:此外,比较容易比较的东西才有意义。如果在它们相等的情况下很难比较数据(例如,如果它们相等,长字符串会从两个字符串中读取大量数据[或开头相同,并且仅在最后几个字符中不同的字符串] . 所以几乎没有节省。这同样适用于一个有一堆成员的类,这些成员通常几乎都是一样的,但有一两个字段不是,等等。另一方面,如果你有一个“客户” data” 类,它有一个整数客户 ID 必须是唯一的,那么只比较客户 ID 将是“便宜的”,但复制客户姓名、地址、电话号码和其他客户数据会很昂贵. [当然,在这种情况下,为什么它不是(智能)指针或引用?]。

如果数据在不同的处理器之间“共享”(多个线程访问相同的数据),那么它可能会有所帮助[特别是如果经常读取这个值,并且经常使用与以前相同的值写入]。这是因为从其他处理器的缓存中“踢出”旧值是昂贵的,并且您只想在实际更改某些内容时这样做。

当然,只有在处理您知道绝对处于性能热路径的最前沿的代码时,担心性能才是有意义的。在其他任何地方,使代码尽可能易于阅读、清晰和简洁始终是最佳选择——通常,这也将使编译器更能够确定实际发生的情况并确保最佳优化结果。

于 2013-05-09T21:50:23.673 回答
4

指令流水线越深(至少在英特尔平台上它只会越来越深),分支预测错误的成本就越高。

当一个分支预测错误时,来自错误预测路径的一些指令仍然在流水线中移动。对这些指令执行的所有工作都被浪费了,因为如果分支被正确预测,它们就不会被执行

所以是的,添加一个ifint 代码实际上会损害性能。写入将被 L1 缓存,可能会持续很长时间。如果写入必须可见,则操作必须互锁才能开始。

于 2013-05-09T21:50:30.490 回答
2

这种模式在 Qt 中很常见,其中 API 高度基于信号和插槽。这种模式有助于避免循环连接情况下的无限循环。

正如@remus-rusanu 和@mats-petersson 所指出的,在您的情况下,如果不存在信号,则此代码只会降低性能。

于 2013-05-10T02:52:37.457 回答