When multiple goroutines concurrently access the same data at the same time, the concurrent access operations must be serialized. The serialization of reads and writes in Go can be guaranteed through channel communication or other synchronization primitives (such as mutex locks, read-write locks in the sync package, and atomic operations in sync/atomic).
Happens Before
In a single goroutine, the behavior of reading and writing must be consistent with the execution order specified by the program. In other words, compilers and processors can reorder instructions in a single goroutine without changing the behavior defined by the language specification.
a := 1 b := 2
Due to instruction reordering, b := 2
may be executed before a := 1
. In a single goroutine, the adjustment of the execution order will not affect the final result. But problems may arise in multiple goroutine scenarios.
var a, b int // goroutine A go func() { a := 5 b := 1 }() // goroutine B go func() { for b == 1 {} fmt.Println(a) }()
When executing the above code, goroutine B is expected to output 5 normally, but due to instruction reordering, b := 1
may be executed before a := 5
, eventually goroutine B may output 0.
“Note: The above example is an incorrect example and is for illustration only.
”
In order to clarify the requirements for read and write operations, Go introduced happens before
, which represents a partial ordering relationship for performing memory operations.
The role of happens-before
When multiple goroutines access shared variables, they must establish synchronization events to ensure the happens-before condition to This ensures that reads can observe expected writes.
What is Happens Before
If event e1 occurs before event e2, then we say that e2 occurs after e1. Likewise, if e1 does not occur before e2 nor after e2, then we say that e1 and e2 occur simultaneously.
In a single goroutine, the order of happens-before is the order of program execution. So what is the order of happens-before? Let's look at the conditions below.
If the read operation r and write operation w for a variable v meet the following two conditions, r will allow to observe w:
r does not occur before w. No other write operation occurs after w and before r.
In order to ensure that a read operation r of variable v can observe a specific write operation w, it is necessary to ensure that w is the only write operation allowed to be observed by r. Then, if r and w both satisfy the following conditions, r can ensure observes w:
w occurs before r. Other write operations occur before w and after r.
There is no concurrency in a single goroutine. These two conditions are equivalent. Lao Xu expanded on this basis and found that these two sets of conditions are equally equivalent for a single-core operating environment. In the case of concurrency, the latter set of conditions is more stringent than the first set.
If you are confused, you are right! Lao Xu was also confused at first. These two sets of conditions were the same. For this reason, Lao Xu specially compared it repeatedly with the original text to ensure that the above understanding was correct.
Let’s change our thinking and conduct reverse reasoning. If the two sets of conditions are the same, then there is no need to write the original text twice. Sure enough, the matter is not simple.
Before continuing the analysis, I would like to thank my Chinese teacher. Without you, I would not be able to discover their differences.
r does not occur before w
, then the possible situation of r is that r occurs after w or at the same time as w, as shown in the figure below (solid indicates that it can occur at the same time).
No other write operation occurs after w and before r
, then other writes w' may occur before w or at the same time as w, also It may occur after r or at the same time as r, as shown in the figure below (solid indicates that it can occur at the same time).
The second set of conditions is very clear. w occurs before r and other write operations can only occur before w or after r, as shown below (empty spaces indicate that they cannot be performed at the same time ).
#At this point you should understand why the second set of conditions is more stringent than the first set of conditions. Under the first set of conditions, w is allowed to be observed, and in the second set, w is guaranteed to be observed.
Synchronization in Go
The following are some synchronization events agreed in Go, which can ensure that the program follows the happens-before principle, thus Make concurrent goroutines relatively orderly.
Go的初始化
程序初始化运行在单个goroutine中,但是该goroutine可以创建其他并发运行的goroutine。
如果包p导入了包q,则q包init函数执行结束先于p包init函数的执行。main函数的执行发生在所有init函数执行完成之后。
goroutine的创建结束
goroutine的创建先于goroutine的执行。老许觉得这基本就是废话,但事情总是没有那么简单,其隐含之意大概是goroutine的创建是阻塞的。
func sleep() bool { time.Sleep(time.Second) return true } go fmt.Println(sleep())
上述代码会阻塞主goroutine一秒,然后才创建子goroutine。
goroutine的退出是无法预测的。如果用一个goroutine观察另一个goroutine,请使用锁或者Channel来保证相对有序。
Channel的发送和接收
Channel通信是goroutine之间同步的主要方式。
Channel的发送动作先于相应的接受动作完成之前。
无缓冲Channel的接受先于该Channel上的发送完成之前。
这两点总结起来分别是开始发送
、开始接受
、发送完成
和接受完成
四个动作,其时序关系如下。
开始发送 > 接受完成 开始接受 > 发送完成
“注意:开始发送和开始接受并无明确的先后关系
”
Channel的关闭发生在由于通道关闭而返回零值接受之前。
容量为C的Channel第k个接受先于该Channel上的第k+C个发送完成之前。
这里使用极限法应该更加易于理解,如果C为0,k为1则其含义和无缓冲Channel的一致。
Lock
对于任何sync.Mutex或sync.RWMutex变量l以及n
假设n为1,m为2,则第二次调用l.Lock()返回前一定要先调用l.UnLock()。
对于sync.RWMutex的变量l存在这样一个n,使得l.RLock()的调用返回在第n次l.Unlock()之后发生,而与之匹配的l.RUnlock()发生在第n + 1次l.Lock()之前。
不得不说,上面这句话简直不是人能理解的。老许将其翻译成人话:
有写锁时:l.RLock()的调用返回发生在l.Unlock()之后。
有读锁时:l.RUnlock()的调用发生在l.Lock()之前。
“注意:调用l.RUnlock()前不调用l.RLock()和调用l.Unlock()前不调用l.Lock()会引起panic。
”
Once
once.Do(f)中f的返回先于任意其他once.Do的返回。
不正确的同步
错误示范一
var a, b int func f() { a = 1 b = 2 } func g() { print(b) print(a) } func main() { go f() g() }
这个例子看起来挺简单,但是老许相信大部分人应该会忽略指令重排序引起的异常输出。假如goroutine f指令重排序后,b=2
先于a=1
发生,此时主goroutine观察到b发生变化而未观察到a变化,因此有可能输出20
。
“老许在本地实验了多次结果都是输出
”00
,20
这个输出估计只活在理论之中了。
错误示范二
var a string var done bool func setup() { a = "hello, world" done = true } func doprint() { if !done { once.Do(setup) } print(a) } func twoprint() { go doprint() go doprint() }
这种双重检测本意是为了避免同步的开销,但是依旧有可能打印出空字符串而不是“hello, world”。说实话老许自己都不敢保证以前没有写过这样的代码。现在唯一能想到的场景就是其中一个goroutine doprint执行到done = true
(指令重排序导致done=true
先于a="hello, world"
执行)时,另一个goroutine doprint刚开始执行并观察到done的值为true从而打印空字符串。
The above is the detailed content of Vernacular Go memory model Happen-Before. For more information, please follow other related articles on the PHP Chinese website!

Go uses the "encoding/binary" package for binary encoding and decoding. 1) This package provides binary.Write and binary.Read functions for writing and reading data. 2) Pay attention to choosing the correct endian (such as BigEndian or LittleEndian). 3) Data alignment and error handling are also key to ensure the correctness and performance of the data.

The"bytes"packageinGooffersefficientfunctionsformanipulatingbyteslices.1)Usebytes.Joinforconcatenatingslices,2)bytes.Bufferforincrementalwriting,3)bytes.Indexorbytes.IndexByteforsearching,4)bytes.Readerforreadinginchunks,and5)bytes.SplitNor

Theencoding/binarypackageinGoiseffectiveforoptimizingbinaryoperationsduetoitssupportforendiannessandefficientdatahandling.Toenhanceperformance:1)Usebinary.NativeEndianfornativeendiannesstoavoidbyteswapping.2)BatchReadandWriteoperationstoreduceI/Oover

Go's bytes package is mainly used to efficiently process byte slices. 1) Using bytes.Buffer can efficiently perform string splicing to avoid unnecessary memory allocation. 2) The bytes.Equal function is used to quickly compare byte slices. 3) The bytes.Index, bytes.Split and bytes.ReplaceAll functions can be used to search and manipulate byte slices, but performance issues need to be paid attention to.

The byte package provides a variety of functions to efficiently process byte slices. 1) Use bytes.Contains to check the byte sequence. 2) Use bytes.Split to split byte slices. 3) Replace the byte sequence bytes.Replace. 4) Use bytes.Join to connect multiple byte slices. 5) Use bytes.Buffer to build data. 6) Combined bytes.Map for error processing and data verification.

Go's encoding/binary package is a tool for processing binary data. 1) It supports small-endian and large-endian endian byte order and can be used in network protocols and file formats. 2) The encoding and decoding of complex structures can be handled through Read and Write functions. 3) Pay attention to the consistency of byte order and data type when using it, especially when data is transmitted between different systems. This package is suitable for efficient processing of binary data, but requires careful management of byte slices and lengths.

The"bytes"packageinGoisessentialbecauseitoffersefficientoperationsonbyteslices,crucialforbinarydatahandling,textprocessing,andnetworkcommunications.Byteslicesaremutable,allowingforperformance-enhancingin-placemodifications,makingthispackage

Go'sstringspackageincludesessentialfunctionslikeContains,TrimSpace,Split,andReplaceAll.1)Containsefficientlychecksforsubstrings.2)TrimSpaceremoveswhitespacetoensuredataintegrity.3)SplitparsesstructuredtextlikeCSV.4)ReplaceAlltransformstextaccordingto


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

SublimeText3 Linux new version
SublimeText3 Linux latest version

SublimeText3 English version
Recommended: Win version, supports code prompts!

Atom editor mac version download
The most popular open source editor
