【问题标题】:Can an expression containing post increment execute in parallel with other parts of that expression in C++?包含后增量的表达式可以与 C++ 中该表达式的其他部分并行执行吗?
【发布时间】:2017-02-11 03:05:37
【问题描述】:

我从以下答案中提出了这个问题: Efficiency of postincrement v.s. preincrement in C++

我找到了这个表达式:

a = b++ * 2;

他们说,上面的b++ 可以与乘法并行运行。

b++ 如何与乘法并行运行?

我对该程序的理解是: 首先,我们将 b 的值复制到一个临时变量,然后增加 b,最后将 2 与该临时变量相乘。 我们不是乘以 b 而是乘以那个临时变量,那么它将如何并行运行?

我从另一个答案 Is there a performance difference between i++ and ++i in C++? 获得了关于临时变量的上述想法

【问题讨论】:

  • 我认为他们的意思是可以在评估a的值之后发生增量,并且a的值不必等待增量完成增量。跨度>
  • 我从来没有想过这个,。这个问题给了我一个新的思考维度..
  • 我不能代表那些写了你链接的答案的人,但你应该看看instruction pipelining
  • 请定义“并行”。如果我们谈论的是 c++ 理论内存模型,那么操作是顺序的(并且彼此之间严格排序)。 as-if 规则可以允许指令指令重新排序以提供性能优势。指令流水线也将发挥作用,但永远不会有并行性。
  • @PaulHK:指针往往会破坏优化器的别名检测。基本上,*b++ 可以更改 any 整数,除非另有明确证明。这通常会迫使编译器插入额外的负载。而且由于内存负载比普通算术昂贵得多(10x-100x),这通常是一种悲观。事实上,今天仍然可行的主要手动优化是从循环中提升指针取消引用,当您知道它不会别名其他变量时。 (C99 引入了restrict 来帮助优化器解决这个问题)

标签: c++ parallel-processing


【解决方案1】:

你说的是instruction level parallelism。在这种情况下,处理器可以在 b 的副本上执行增量,同时也乘以旧的 b。 这是处理器级别的非常细粒度的并行性,通常您可以期望它会给您带来一些优势,具体取决于架构。

在预增量的情况下,增量操作的结果必须在处理器的管道中等待,然后才能执行乘法运算,因此会给您带来惩罚。 但是,这在语义上并不等效,因为 a 的值会有所不同。

【讨论】:

    【解决方案2】:

    @SimpleGuy 的回答是一个非常合理的初步近似值。问题是,它假设了简单理论模型(没有并行化)和现实世界之间的中间点。这个答案试图查看一个更现实的模型,仍然没有假设一个特定的 CPU。

    要意识到的主要事情是真正的 CPU 具有寄存器和缓存。这些存在是因为内存操作比简单的数学要昂贵得多。整数增量和整数位移的并行化(*2 在真实 CPU 上优化为 <<1)是一个小问题;优化器将主要着眼于避免负载停顿。

    所以我们假设ab 不在CPU 寄存器中。相关的内存操作有LOAD bSTORE aSTORE b。一切都以LOAD b 开头,因此优化器可能会尽可能地将其向上移动,甚至在可能的前一条指令之前(别名是这里的主要关注点)。 STORE b 可以在 b++ 完成后立即启动。 STORE a 可以发生在 STORE b 之后,因此它被一条 CPU 指令(<<1)延迟并不是什么大问题,并且通过并行化这两个操作几乎没有什么好处。

    【讨论】:

    • 但是是否可以并行运行b++ * 2 中的所有指令? (记住这个临时变量)如果是 ++b * 2 ,我们肯定无法并行运行所有指令。
    • @AlMamun:所以至少有5个操作,其中3个是内存操作。显然你不能并行运行内存操作;在存储变量时无法加载它。但是您可以b 的存储与a 的乘法(位移)并行化。
    【解决方案3】:

    b++可以并行运行的原因如下

    b++ 是后自增,这意味着变量的值在使用后会自增。下面一行可以分为两部分

    a = b++ * 2
    

    第 1 部分:b2 相乘

    第 2 部分:b 的值增加1

    由于上述两个不依赖彼此,它们可以并行运行

    Hard case 是 pre-increment,即在使用前先递增

    a = ++b * 2
    

    零件本来是

    第 1 部分:b 的值增加1

    第 2 部分:将(新)b2 相乘

    从上面可以看出,第二部分只有在第一部分执行后才能运行,所以有依赖关系因此没有并行性。

    【讨论】:

    • 它们在你的两种情况下都非常依赖
    • 在您的第一种情况下,您没有考虑该临时变量。 2 不是直接与 b 相乘,而是与作为 b 副本的临时变量相乘。
    • 虽然善意,但我认为这个答案是不正确的。
    • @RichardHodges 请指教
    • b++ * 2 表示:“将 B 复制到一个临时对象中,将结果乘以 2,在 b 上调用 ++,丢弃结果,然后返回 temp*2 的结果”。 b 上的 ++ 操作按顺序发生在复制之后但分号之前。 ++ 因此依赖于正在获取的副本。
    猜你喜欢
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 2013-07-02
    相关资源
    最近更新 更多