变量赋值是原子吗?

Fil*_*und 6 concurrency go

如果我有两个线程同时修改结构上的字符串字段,我是否总是会看到分配给该字段的一个或另一个字符串,但没有别的?

Jim*_*imB 12

不.如果你需要原子操作,那就有了sync/atomic.

转到内存模型将所有相关的细节.从Memory Model文档的顶部:

修改由多个goroutine同时访问的数据的程序必须序列化此类访问.

要序列化访问,请使用通道操作或其他同步原语(如syncsync/atomic 包中的原语)保护数据.

  • 赋值不是原子的,引用文档中的第一句话就暗示了这一点,并且在描述可观察性条件时通过文档强化了这一点。如果这不满意,我建议您向 go 项目提出问题,以便在文档中进行澄清。 (3认同)

Quâ*_*Mai 5

截至今天,Go 内存模型的 2022 年 6 月 6 日版本保证不大于机器字的内存访问是原子的。

\n
\n

否则,对不大于机器字的内存位置 x 的读取 r 必须观察到某些写入 w,使得 r 不会发生在 w 之前,并且不存在写入 w\' 使得 w 发生在 w\' 和 w\ 之前' 发生在 r 之前。也就是说,每次读取都必须观察先前或并发写入写入的值。

\n
\n

但是,字符串肯定比机器字大,因此不能保证您的访问是原子的。在这种情况下,结果是未指定的,但它很可能是来自不同写入的不同部分的交错。

\n
\n

鼓励读取大于单个机器字的内存位置,但不要求满足与字大小的内存位置相同的语义,观察单个允许的写入 w。出于性能原因,实现可能会将较大的操作视为一组未指定顺序的单独机器字大小的操作。这意味着多字数据结构上的竞争可能会导致与单次写入不对应的不一致值。当值取决于内部(指针、长度)或(指针、类型)对的一致性时,就像大多数 Go 实现中的接口值、映射、切片和字符串的情况一样,此类竞争反过来可能会导致任意结果内存损坏。

\n
\n

请注意,它sync/atomic不仅提供原子性,还提供顺序一致性。因此,对于不大于机器字的访问,sync/atomic仅提供额外的顺序一致性。

\n
\n

包中的APIsync/atomic统称为\xe2\x80\x9catomic操作\xe2\x80\x9d,可用于同步不同goroutines的执行。如果原子操作 A 的效果可以通过原子操作 B 观察到,则 A 在 B 之前同步。程序中执行的所有原子操作的行为就好像按某种顺序一致的顺序执行。

\n前面的定义与 C++\xe2\x80\x99s 顺序一致原子和 Java\xe2\x80\x99s 易失性变量具有相同的语义。

\n
\n

  • @ahmetalpbalkan 字符串不是不可变的切片指针。尽管语言没有指定,但 Go 中字符串的当前实现是指向有效负载的指针和指示字符串长度的字段,这使得对象的大小是机器字的大小的两倍。 (2认同)