当应用于原始类型时,它是否是在赋值之前检查相等性的过早悲观形式?

时间:2016-03-09 15:38:50

标签: c++ c

拥有经常修改非本地(成员)变量的代码(在单线程场景中,使用基本类型),过早的悲观化只是分配而不检查是否有必要(考虑到状态的修改没有其他方面)效果如下面的代码所示)?

e.g:

static int someState = 0;
void foo(int newState)
{
  /* Which is better? This...*/
  someState = newState; /*Assign regardless*/

  /* ... or this... */
  if (someState != newState)
  {
    someState = newState; /*Only write when required*/ 
  }
}

我总觉得支票是多余的,想听听你的意见。

  • 读取和写入之间的速度是否有很大差异,以至于在经常进行状态更改时考虑读取检查?
  • 额外检查是否具有高度内容性?

我可能会对此进行描述,是的,但我对这类事情的社区共识感到疑惑。无论如何,我大多只是执行任务,而且我想知道这是否是它的主要用途。

4 个答案:

答案 0 :(得分:2)

像往常一样,这一切都取决于。首先,您应该尽量在代码中只有一个位置设置值(例如,setter或属性,具体取决于您使用的语言)。

如果您的应用程序使用观察者,或者如果值更改需要采取某些操作,则通常最好检查值是否相同,并且仅在值更改时执行操作。因此,任何调用setter的人都可以知道它总是很便宜。这会产生积极影响,即代码中只有一个位置需要进行优化。

答案 1 :(得分:2)

  

使用原始类型

  

过早的悲观化只是分配而不检查是否有必要?

更糟。它正在添加一个不必要的读取,比较和条件跳转到本应该写入的内容。

  

用户定义的类型怎么样?

让期望的分配数量= N

假设冗余分配的次数为U

让平等比较成本= C

让分配成本= A

因此冗余分配的比率为R = U / N

我们可以通过检查= RNA

来保存

这样做的成本= NC

调用检查时:分配总成本= NC +(1-R)NA

什么时候不费心去检查:作业成本= NA

因此,为了确定是否值得检查平等,我们只需要满足不平等:

NA> NC + NA - RNA

NA-NC + NA> -RNA

-NC> -RNA

NC< = RNA

NC / NA< = R

C / A< = R

R> C / A

因此,如果预期冗余分配的比率大于支票成本的比率(与分配成本相比),那么值得优化。

有人可以查看我的数学吗?已经有一段时间......

答案 2 :(得分:1)

在你提到的情况下,对于没有其他效果会发生的原始类型,我说总是分配。这不是一个过早的悲观化。无论哪种方式,结果都是相同的,您可以节省负担并进行比较。我认为在分配之前添加相等性测试是过早的悲观化。

答案 3 :(得分:1)

有几件事需要考虑:

  • 这些类型是原始的吗?
  • 如果没有,这些类型的比较和分配有多贵?
  • 如果是,这是变量volatile

对于原始的非易失性类型,第一个选项应该更快。它是存储与加载+比较+分支或加载+比较+分支+存储。对于现代处理器上的原始类型,存储与加载几乎相同,因此第一个选项应该总是更快。 如果条件不遵循任何常规模式,则尤其如此,并且分支预测将不起作用。在这种情况下,分支可能需要很多周期。

对于volatile变量,选择取决于你需要什么语义(它是某些硬件的控制寄存器,写入内存位置会导致某些操作,通过网络传输等等吗?)

对于类,选择取决于比较的相对成本和分配和概率的相等性。在第一个选项中,总是有一个赋值。在第二个选项中:如果值相等,则只有比较和分支;如果没有,比较,分支和分配。

一般来说,它是:

Ta vs. (Tc + Tb) * p + (Tc + Tb + Ta) * (1 - p)

其中Ta是赋值时间,Tc - 比较,Tb - 分支(如果类是复数则可以忽略),p是相等值的概率。

另请注意,某些类可以在其赋值运算符中包含此检查。