This is a creation in Article, where the information may have evolved or changed.
At the time of development, we often encounter scenarios where it is necessary to execute or initialize once, for example, Singleton mode or initialization of the system when it is turned on. General language common practice is to use mutually exclusive operation to set the flag variable, by judging the value of the flag variable to determine whether to execute the relevant code; The implementation of the Golang language is very simple, just one line of code, as follows:
Import "Sync"
var once sync. Once
Func init () {
Initialize Code
}
Once. Do (init)//Just one line of code, clear structure, at a glance
So once. How is the Do () method implemented? Let's parse an operation implemented by Golang:
First, "Sync" is a reference package that is implemented in the package; Once is a struct object defined, as follows:
Type Once struct {
M Mutex
Done UInt32
}
See here, we basically should be able to guess the once. Do () Implementation of the idea, ONCE.M is a mutex, in the Do () operation, the mutual exclusion operation; Once.done is a flag variable that indicates whether do () is performed. The specific implementation of Do () is as follows:
Func (o *once) do (f func ()) {
If atomic. LoadUint32 (&o.done) = = 1 {
Return
}
O.m.lock ()
Defer O.m.unlock ()
If O.done = = 0 {
Defer automic. StoreUint32 (&o.done, 1)
F ()
}
}
The
implementation idea is basically consistent with our guess, which introduces the atomic Action Pack import "Sync/atomic" through automic. The LoadUint32 and AUTOMIC.STOREUINT32 operations implement the load and storage of the flag variable Once.done, so that the implementation of the more granular atomic operation can further improve the speed of the system processing and reduce the unnecessary waiting of the co-process on the mutex.