std::atomic 变量与非原子变量的性能如何?

问题描述 投票:0回答:1

我很好奇在应用程序中使用

std::atomic<float>
与普通
float
的性能。我也很好奇是什么影响了这个。我经常看到有关原子与互斥体性能的主题,但我发现很难找到有关原子与非原子的信息。

我并不是用它来选择是否使我的代码线程安全,只是想了解所涉及的开销。

(编辑:在最初的问题中,我给出了一个示例(见下文),该示例应该说明实现的更改,而不是询问有关该代码的具体问题。这似乎让人们对我的内容感到困惑问了所以我把它拿出来了。)

我基本上想知道影响 std::atomic 性能的广泛因素是什么。是平台吗?它们的使用方式?使用两个线程访问大约相同数量的原子是否比一个线程 95% 的时间访问它们而另一个线程偶尔访问原子要慢?

另外,

std::atomic<int>
std::atomic<float>
在这方面有什么区别吗?

提前致谢,

亚当


原始问题的示例:

基本上,我尝试制作一百万个浮点并向它们写入值 200 次。这对我来说花了 0.87 秒。一旦我将它们更改为

std::atomic<float>
,这大约需要 2.5 秒。因此,这意味着使用成本大约是原来的 3 倍
std::atomic<float>

我尝试了这个,但为了读取值而不是写入,发现正常的

float
std::atomic<float>
花费相同的时间。

但这会受到其他因素的影响吗?如果另一个线程正在写入/读取我的原子,这是否会减慢其他对同一变量的读取/写入速度?大概是这样,但是我怎样才能更好地理解这一点?

c++ multithreading performance thread-safety atomic
1个回答
17
投票

没有排序参数(即默认值)的原子存储非常昂贵,因为编译器会发出额外的排序指令。

x86
上,浮点数的默认(顺序一致)原子存储如下所示:

atomic<float> f;
f.store(3.14);

gcc
产生以下指令:

0x00000000004006d0 <+0>:     movl   $0x4048f5c3,0x20096a(%rip)        # 0x601044 <f>
0x00000000004006da <+10>:    mfence

mfence
指令很昂贵,因为它确保对其他内核的直接可见性(即导致存储缓冲区被刷新)。

您可以尝试在不订购的情况下运行测试:

f.store(3.14, std::memory_order_relaxed);

这将消除

mfence
,并且可能会显示出显着的性能差异。它在某些平台上更接近(如果不是相等的话)非原子商店。

在这方面,

std::atomic<int>
std::atomic<float>
之间有什么区别吗?

假设两者都是无锁的,可能不是。排序限制是导致性能降低的原因。

© www.soinside.com 2019 - 2024. All rights reserved.