猿问

何时以及为什么使用 go 的 atomic 包比较 =,+

As go 的文档说明:

由 AddT 函数实现的加法操作是原子等价的:

*地址 += 增量

返回*地址

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

这是我的问题:

为什么我应该使用“atomic.AddT”而不是“+”?

为什么 'atomic.LoadT' 不是 '=' ?

'=' 和 '+' 不是异常的吗?

谁能给我一个显示它们之间差异的例子?


月关宝盒
浏览 173回答 3
3回答

扬帆大鱼

首先,你需要了解 go memory 模型:https://golang.org/ref/mem要理解的关键点是,goroutine 中变量写入的影响不一定对另一个 goroutine 可见,就像写入 goroutine 观察它们的方式一样。也就是说,如果一个 goroutine 将一个值写入一个变量a,然后再写入另一个变量b,另一个 goroutine 可能会以未指定的顺序看到这些写入。这就是为什么您需要像通道或互斥锁这样的并发原语。在通道操作或互斥操作之前发生的任何事情都将在此时对所有 goroutine 可见。原子操作提供了类似的保证,尽管内存模型没有明确指定。使用原子编写代码并不容易。您必须考虑所有可能的执行交错以确保没有竞争。坚持使用通道和互斥锁。正确的代码比快速但活泼的代码要好。

森林海

想象一下,有 5 个 goroutine 同时访问初始化为 0 的同一个内存/源并试图增加它。常规增量“+”操作会导致数据竞争,因为由于同时操作无法保证状态被正确更新。最后,不能保证共享变量的值为 5在这种情况下,原子操作会有所帮助,因为它们会锁定内存以供 goroutine 进行安全操作,因此不会观察到数据竞争您还可以使用通道或互斥锁来锁定状态并安全操作,更推荐

慕容708150

您根本 不应该使用包atomic。正如包装文档明确指出的那样包 atomic 提供了用于实现同步算法的低级原子内存原语。这些功能需要非常小心才能正确使用。除了特殊的低级应用程序外,最好使用通道或同步包的工具来完成同步。通过通信共享内存;不要通过共享内存进行通信。它仅供专家使用。你问:“'=' 和 '+' 不是异常的吗?” 不!Go 中没有任何东西(!)是原子的,除了包 atomic 中的原语(因此得名)、包同步提供的内容和通道操作。所以不,您不能同时使用=, +, -,/等。而且你真的不应该编写假设某些东西是原子的就是正确的代码。始终提供正确的同步(通过包同步)或通过渠道。
随时随地看视频慕课网APP

相关分类

Go
我要回答