x86 放松订购性能
x86 relaxed ordering performance?
既然英特尔提供了强大的硬件内存模型,那么在C++11程序中使用"memory_order_relaxed"有什么好处吗?或者只是将其保留为默认值"顺序一致",因为它没有区别?
像计算机科学中的大多数答案一样,答案是"这取决于"。
首先,顺序一致的排序永远不会带来任何惩罚的想法是不正确的。根据您的代码(以及可能的编译器),它可以并且将会带来惩罚。
其次,要对内存排序约束做出明智的决策,您需要考虑(并理解)如何使用所涉及的数据。
memory_order_relaxed对于需要原子的独立计数器之类的东西很有用,但与其他东西没有直接关系,因此它不需要与任何"其他东西"保持一致。典型的示例是引用计数,例如在shared_ptr
或std::string
的一些较旧的实现中。在这种情况下,我们只需要确保计数器以原子方式递增和递减,并且对它的修改对所有线程都是可见的。但是,特别是,没有任何相关数据需要保持一致,所以我们不太关心它相对于其他任何东西的排序。
顺序一致排序几乎处于相反的极端。这可能是最容易应用的 - 你编写的代码就像它是单线程的一样,并且实现确保它正常工作(这并不是说你根本不需要考虑线程,但顺序一致的排序通常需要最少的考虑,但通常也是最慢的模型)。
获取/发布一致性通常在您有两个或更多相关信息时使用,并且您需要确保一个信息仅在另一个信息之前/之后可见。对于我最近处理的一个示例,假设您正在构建一个大致类似于内存数据库的东西。您有一些数据,并且有一些元数据(并且您或多或少地单独存储每个元数据)。
元数据(除其他事项外)用于搜索数据库。我们希望确保,如果有人找到一些特定的数据,他们找到的数据实际上将存在于数据库中。
为了确保这一点,我们希望确保数据始终存在于元数据之前,并且至少与元数据一样长。如果有人可以使用元数据搜索数据库,并找到它想要使用的一些数据,而这些数据实际上并不存在,那么数据库将是不一致的。
因此,在这种情况下,当我们添加记录时,我们需要确保先添加数据,然后再添加元数据 - 并且编译器不得重新排列两者。同样,当我们删除记录时,我们需要删除元数据(这样没有人会找到数据),然后删除数据本身。就数据本身而言,我们很可能有一个引用计数来跟踪当前有多少客户端正在访问该数据,以确保我们不会在有人尝试使用它时删除它。
因此,在这种情况下,我们可以对元数据和数据使用获取/释放语义,并对引用计数使用宽松排序。或者,如果我们想让我们的代码尽可能简单,我们可以自始至终使用顺序一致性——即使它可能(并且可能会)至少带来一些惩罚。
始终使用使代码正确所需的最小保证。
不多也不少。
这样,您可以避免对实现的任何不必要的依赖,从而降低任何移植成本,并且仍然可以获得最快的程序。
当然,如果你确定你永远不会关心移植你的任何代码,那么在你知道它在你的平台上无关紧要的地方采取更强有力的保证可能会使证明它的正确性更容易。
更难误用、更容易推理或更短也是使用性能较低的结构的完全接受的原因。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 为什么constexpr的性能比正常表达式差
- 为x86而非x64编译时出错
- 在类中使用随机生成器时出现性能问题
- C++如何仅使用MOV在x86上实现发布和获取
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 在 C/C++ 中在特定地址边界上对齐内存是否仍能提高 x86 性能?
- x86 中不同数学函数的性能
- x86和x86_64中浮点和双精度之间的性能差异
- x86 放松订购性能
- x64 性能与 x86 的比较