当前位置:网站首页>[translation] go references - the go memory model | memory model for Chinese translation of official golang documents
[translation] go references - the go memory model | memory model for Chinese translation of official golang documents
2022-06-12 12:09:00 【Just want to call Yoko】
This article is published synchronously in : [ translate ] Go References - The Go Memory Model | golang Memory model for Chinese translation of official documents | yoko blog
Preface
This translation corresponds to the original
title :The Go Memory Model - Go References
author :Go Official documents
Address :https://golang.org/ref/mem
This document indicates yoko remarks The content of is my own notes , The rest are translations of the original English text .
Catalog
- brief introduction
- Suggest
- Happens Before
- Sync
- init function
- Create coroutines
- Destroy the process
- Use channel signal communication
- lock
- Once
- Demonstrate the wrong use of synchronization primitives
brief introduction
golang The memory model of specifies the conditions on which you want to achieve this effect . What effect is achieved ? That is, modify a variable in a coroutine , When another coroutine reads this variable, it is necessary to ensure that the modified value is read .
Suggest
If the program modifies the data accessed by multiple processes at the same time , Then these access operations must be serialized .
To ensure serial access , have access to golang Of channel Operate or use sync and sync/atomic Synchronization primitives in the package to protect data .
If you need to read the rest of this document to understand the behavior of your program , So you're a little too smart .
forehead , Don't be too clever .
Happens Before
In a process , The actual order of execution of read and write operations must ensure that the behavior they represent is consistent with the order specified in the program . in other words , The compiler and the processor will only reorder the read and write operations within the collaboration without changing the program semantics . Because of this reordering , The execution sequence observed by one process may be different from that observed by another process . for instance , If a coroutine is executed a=1; b=2;, Another synergy that may be observed is b The update of variables occurs in a Before updating variables .
To illustrate the requirements for read and write operations , We defined happens before, A kind of golang The local execution sequence of a program's memory operations . If the event e1happens before event e2, So let's say e2happens aftere1. alike , If e1 No happens beforee2 also e1 either happens aftere2, So let's say e1 and e2happens concurrently.
yoko remarks :
happens before The defined execution order , It is a kind of confirmation 、 Unique execution sequence .
That is, if I say a happens before b,
that a It must have happened in b Previous , Not allowed a It happened in b After or a and b Simultaneous occurrences occur .
let me put it another way , If there is a It happened in b After or a and b Simultaneous events , Then you can't say a happens before b.
not happens before, This needs special attention .
If I say a not happens before b,
So it could be a It happened in b after ; It could be a and b At the same time .
As long as it's not a It happened in b Just before .
happens after Namely happens before Another way of saying that the subject and object of a statement change their positions , There's nothing to explain this .
In a single process ,happens before Sequence is the sequence described in the program .
The variable v Read operation r allow Observed for variable v Write operations for w(yoko remarks : there allow It means allow , It is possible to observe , It may not be observed ), The following conditions must be met at the same time :
- r
not happens beforew - Nothing else
happens afterw alsohappens beforer Write operations for
If you want to make sure that the variables v Read operation r To observe a specific pair of variables v Write operations for w, namely w yes r The only write operation allowed to be observed . Simply speaking , Make sure that r The observed w, The following conditions must be met at the same time :
- w
happens beforer - Other shared variables v Write operations for either
happens beforew, orhappens afterr
This set of conditions is more restrictive than the first set of conditions . It requires no other write operations and w/rhappens concurrently.
In a process , Because there is no concurrency , So the two definitions are the same : Read operations r The last write operation can be observed w. If a shared variable is accessed by multiple processes . Then we must use synchronous events to establish happens before Condition to ensure that the read operation observes the desired write operation .
The variable v Initialization of , The behavior is the same as doing a write operation in the memory model .
Read and write operations on variables that exceed a machine word length , Its behavior is the same as that of multiple single machine word size operations , Is an unspecified order .
Sync
init function
golang All in the program init function Running in the same process , But this collaboration may create other collaborations , These coroutines may run concurrently .
If p The package introduces q package , that q Of init The function will be fully executed before starting execution p Of init function.
The entry function of the program main.main In all init function Do it after all .
Create coroutines
Start a new process happens before The entrance to the implementation of this new process .
For example, the following program :
var a string
func f() {
print(a)
}
func hello() {
a = "hello, world"
go f()
}
call hello Function will be printed at some point in the future "hello, world", This point in time may be hello After function execution .
Destroy the process
Process exit does not guarantee happens before Any event in the program . For example, the following program :
var a string
func hello() {
go func() { a = "hello" }()
print(a)
}
Assignment statements are not combined with any synchronous events , There is no guarantee that this assignment statement will be observed by any other coroutine . in fact , A radical compiler may remove the entire coroutine statement .
If the impact of one process needs to be observed by other processes , Lock or channel And other synchronization mechanisms to establish an association order .
Use channel signal communication
Use channel Communication is the main method of multiprocess synchronization . Each time to a specific channel Sending is associated with a slave channel Receive matching , Generally, the sending and receiving processes are different .
To the buffered channel send out happens before From the channel Finish receiving .(yoko remarks : namely channel The receiver of the will be blocked , Until other collaborations go channel Sent data )
This procedure :
var c = make(chan int, 10)
var a string
func f() {
a = "hello, world"
c <- 0
}
func main() {
go f()
<-c
print(a)
}
Will ensure printing "hello, world". Yes a Writing happens before Go to channel c send out , Go to channel c send out happens before from channel c Finish receiving , from channel c Finish receiving happens before Print .
Close a channel happens before from channel The receiver of returns 0 value .
In the previous example , take c <- 0 Replace with close(c), The program guarantees the same behavior .
No buffer channel receive happens before To this channel Completion of transmission .(yoko remarks : namely channel The sending place of will be blocked , Until other processes are executed from channel Reading data )
This procedure ( Compared with the above procedure , The send and receive statements are exchanged and no cache is used channel):
var c = make(chan int)
var a string
func f() {
a = "hello, world"
<-c
}
func main() {
go f()
c <- 0
print(a)
}
Printing will also be guaranteed "hello, world". write in a Variable happens before from c receive , from c receive happens before Go to c Completion of transmission , Go to c Completion of transmission happens before Print .
If channel It's buffered ( such as ,c = make(chan int, 1)), Then the program is not guaranteed to print "hello, world".( You may print an empty string , A crash or something ).
The first k The secondary initialization space is C Of channel Reception happens before The first k+C Secondary channel Completion of transmission .
This rule outlines the previous one, which is also about buffering channel The rules of . It allows the use of buffered channel To count semaphores :channel The number of elements inside is equal to the number of semaphores actually used ,channel The size of the initialization space is equal to the maximum number of semaphores that can be used simultaneously , Go to channel Sending an element is equivalent to getting a semaphore , from channel Receiving an element is equivalent to releasing a semaphore . This is a common way to limit concurrency .
This program is work Each element of the list opens a coroutine , But these coroutines are used to limit the initialization size channel Ensure that there are at most three at the same time work In execution .
var limit = make(chan int, 3)
func main() {
for _, w := range work {
go func(w func()) {
limit <- 1
w()
<-limit
}(w)
}
select{}
}
lock
sync The package implements two types of lock data ,sync.Mutex and sync.RWMutex.
For any sync.Mutex or sync.RWMutex Lock variables for l And two times n and m(n < m), Call No n Time l.Unlock()happens before Call No m Time l.Lock() Return .
This procedure :
var l sync.Mutex
var a string
func f() {
a = "hello, world"
l.Unlock()
}
func main() {
l.Lock()
go f()
l.Lock()
print(a)
}
Will ensure printing "hello, world". First call l.Unlock( stay f Function )happens before Second call l.Lock()( stay main Function ) Return , The second time l.Lock() Return happens before Print .
about sync.RWMutex Variable l Any call to l.RLock,l.RLock Block until n Secondary call l.UnLock, also n Time l.RUnlockhappens before The first n+1 Secondary call l.Lock.
yoko remarks :
The description of the read-write lock in the original English text is a bit convoluted , Personal understanding of read-write lock is :
The prerequisite for entering the read lock is , At present, there can be 0~n Read locks have been entered , But no write lock has been entered
The prerequisite for entering the write lock is , Currently, no read lock has been entered , And currently no write lock has been entered
So the original sentence actually means , The read lock can only be accessed after the write lock is released , Write locks can only be accessed after all read locks are released
Once
sync In bag Once Type provides a security mechanism for initializing in a multi - process environment . Multithreading can be a specific function f perform once.Do(f), But there is only one f() Will be performed , And other calls will block until f() completion of enforcement .
Multi process use once.Do(f), Only the one that was executed f() Execute and return , Then the others return .
This procedure :
var a string
var once sync.Once
func setup() {
a = "hello, world"
}
func doprint() {
once.Do(setup)
print(a)
}
func twoprint() {
go doprint()
go doprint()
}
call twoprint It will only call setup once .setup The function will call print Completed before . The result is "hello, world" It prints twice .
Demonstrate the wrong use of synchronization primitives
remember , Read operations r Concurrent write operations may be observed w Result . Even if this happens , It does not mean that r Subsequent readings will also observe the occurrence of r Previous w.
This procedure :
var a, b int
func f() {
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
go f()
g()
}
Possible g Function print first 2 Re print 0.
This fact makes some writing incorrect .
Double check lock is a means to try to avoid redundant synchronous operation . such as ,twoprint The program may be incorrectly rewritten to :
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()
}
But that doesn't guarantee , stay doprint Function , Observed on done The writing of is equivalent to the observation of a Writing . This wrong version may incorrectly print out an empty string instead of "hello, world".
Another misnomer is busy waiting for a variable , It's like :
var a string
var done bool
func setup() {
a = "hello, world"
done = true
}
func main() {
go setup()
for !done {
}
print(a)
}
As I said before , There is no guarantee that main A pair of... Is observed in the function done The writing of means the observation of a Writing , All this program can also print out an empty string . What's worse is , There is no guarantee that done Will be written by main Function observed , Because there is no synchronized event between two threads .main A loop in a function is not guaranteed to end .
There are other scenes with some minor differences on the subject , Like this program .
type T struct {
msg string
}
var g *T
func setup() {
t := new(T)
t.msg = "hello, world"
g = t
}
func main() {
go setup()
for g == nil {
}
print(g.msg)
}
Even if main Function observed g != nil And exit the loop , There's no guarantee main Function can be observed for g.msg Modification of .
All these examples , The solution is the same : Using explicit synchronization primitives .
边栏推荐
- Pseudo instruction of arm instruction set
- Who moved my package lock
- 传统的DOM渲染方式?
- 回溯法, 八皇后
- Why is there no traffic after the launch of new products? How should new products be released?
- 异步路径处理
- Open source project - (erp+ Hotel + e-commerce) background management system
- LeetCode_ Binary search_ Medium_ 162. looking for peaks
- object. Defineproperty basic usage
- TinyMCE series (III) introduction to common TinyMCE APIs
猜你喜欢

Find the median of two ordered arrays (leetcode 4)

In navigation, the solution of adding borders to affect the layout

LeetCode 890. 查找和替换模式(模拟+双哈希表)

QML学习 第二天

MySQL review

LeetCode 1037. 有效的回旋镖(向量叉乘)

创建Servlet项目

Analyze the implementation principle of the onion model, and connect the onion model in your own project

Cookies and sessions

Beyondcompare 4 uses PJ
随机推荐
TinyMCE series (II) TinyMCE plug-in development
First understand the onion model, analyze the implementation process of middleware, and analyze the source code of KOA Middleware
Rich text editor copying pictures in word documents
开源项目-(ERP+酒店+电商)后台管理系统
如何确定首页和搜索之间的关系呢?首页与搜索的关系
mysql复习
Elk construction guide
7-5 complex quaternion operation
Traditional DOM rendering?
异步路径处理
获取本机所有ipv4, ipv6地址
[QNX hypervisor 2.2 user manual] 4.1 method of building QNX hypervisor system
AutoLock 解决加锁后忘记解锁问题
LeetCode 497. Random points in non overlapping rectangles (prefix and + bisection)
Compiling Draco library on Windows platform
转载--win10打开任务管理器就蓝屏的问题
Stress - system pressure simulation tool
How to determine the relationship between home page and search? Relationship between homepage and search
ARM processor mode and register
回溯法, 八皇后