何时以及为什么使用go';s原子包与=、+;

何时以及为什么使用go';s原子包与=、+;,go,Go,正如go的文件所示: 由AddT函数实现的add操作是原子等效的: *addr+=delta 返回*地址 LoadT和StoreT函数实现的加载和存储操作是“return*addr”和“*addr=val”的原子等价物 我的问题是: 为什么我应该使用'atomic.AddT'而不是'+'呢 为什么“atomic.LoadT”不是“=” “=”和“+”不是aomic吗 有谁能给我一个例子来说明它们之间的区别吗?想象一下,有5个goroutine同时访问初始化为0的相同内存/源并尝试递增它。常规增量

正如go的文件所示:

由AddT函数实现的add操作是原子等效的:

*addr+=delta

返回*地址

LoadT和StoreT函数实现的加载和存储操作是“return*addr”和“*addr=val”的原子等价物

我的问题是:

为什么我应该使用'atomic.AddT'而不是'+'呢

为什么“atomic.LoadT”不是“=”

“=”和“+”不是aomic吗


有谁能给我一个例子来说明它们之间的区别吗?

想象一下,有5个goroutine同时访问初始化为0的相同内存/源并尝试递增它。常规增量“+”操作将导致数据竞争,因为无法保证由于同时操作而正确更新状态。最后,无法保证共享变量的值为5

在这种情况下,原子操作会有所帮助,因为它们通过goroutine锁定内存以进行安全操作,因此不会观察到数据竞争


您还可以使用通道或互斥锁来锁定状态并安全运行,这是更推荐的

您不应该在所有中使用package atomic

正如文件包中明确指出的那样

packageatomic提供了对存储有用的低级原子内存原语 实现同步算法

这些功能需要非常小心才能正确使用。除特殊情况外, 在低级应用程序中,使用通道或 同步包的设施。通过交流分享记忆;不要 通过共享内存进行通信

它只供专家使用

你问:“难道不是“=”和“+”aomic吗?”不!Go中没有任何(!)是原子的,除了package atomic中的原语(因此得名)、package sync提供的内容和通道操作


因此,不能同时使用
=
+
-
/
等操作。而且你绝对不应该编写假定某个东西是原子的代码。始终提供正确的同步(通过软件包同步)或通过频道。

首先,您需要了解go memory型号:

要理解的关键点是,一个goroutine中变量写入的效果不一定对另一个goroutine可见,就像写入goroutine观察它们一样。也就是说,如果一个goroutine将一个值写入一个变量
a
,然后写入另一个变量
b
,那么另一个goroutine可能会以未指定的顺序看到这些写入。这就是为什么需要通道或互斥体等并发原语。在通道操作或互斥操作之前发生的任何事情都将在此时对所有goroutine可见

原子操作提供了类似的保证,尽管内存模型没有明确指定

使用原子学编写代码并不容易。你必须考虑所有可能的执行交织,以确保没有种族。坚持使用通道和互斥体。正确的代码比快速但活泼的代码好