In the process of writing code, we often encounter code that only needs to run once for the global angle, such as global initialization operation, single instance mode in design mode. For the singleton mode, there are starving mode and lazy mode in java, which are implemented with synchronized synchronization keyword. Its purpose is to initialize the object only once, and it is better to ensure that it can be initialized again when it is used, so as to avoid wasting resources too early in initialization, or the two initialization can destroy the instance uniqueness of the singleton mode.
The sync package of Go language provides a Once type to ensure global uniqueness. It is implemented through the Do(f func()) method. Even if the F function changes, it will not be executed. Here is a small example:
package main import ( "fmt" "sync" "time" ) var once sync.Once func main() { //Once loop calls the firstMethod function 10 times, but only once for i := 0; i < 10; i++ { once.Do(firstMethod) fmt.Println("count:---", i) } //Start 10 processes, and call the secondMethod function with once, but the function will not be executed. //Print only ------ i for i := 0; i < 10; i++ { go func(i int) { once.Do(secondMethod) fmt.Println("-----", i) }(i) } //Wait 1min for the main process and wait for the above 10 processes to be completed time.Sleep(1 * time.Second) } func firstMethod() { fmt.Println("firstMethod") } func secondMethod() { fmt.Println("secondMethod") }
The output of the running program is as follows:
firstMethod count:--- 0 count:--- 1 count:--- 2 count:--- 3 count:--- 4 count:--- 5 count:--- 6 count:--- 7 count:--- 8 count:--- 9 ----- 0 ----- 2 ----- 4 ----- 5 ----- 8 ----- 6 ----- 9 ----- 3 ----- 7 ----- 1 Process finished with exit code 0
Then let's analyze:
In the program, a sync.Once type named once is defined first, and then the first for loop in the main function is 10 times, but since the F function in once.Do(f func) is only executed once globally, the firstMethod() function is only executed once; then the second for loop is entered, where the parameter of once.Do(f func) method becomes the secondMethod function. Start 10 processes to call, but because once.Do(secondMethod) and once.Do(firstMethod) use the same instance of once type, the secondMethod function will not be executed in fact. This explains the run result output above.
Check the source code once.go, which has the following explanation:
if once.Do(f) is called multiple times, only the first call will invoke f, even if f has a different value in each invocation. A new instance of Once is required for each function to execute.
If once.Do(f) is called multiple times, only the first call will execute the F function, even if f is a different function. In order for each function to be executed, a different instance of Once is required.
Let's look at the definition of Once type:
type Once struct { m Mutex done uint32 }
In the source code, the mutex m and the flag done are used. Then look at the implementation of the Do method:
func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 { return } // Slow-path. o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1) f() } }
Before calling the Do method every time, use the LoadUint32 function of the atomic package to get the value of the flag bit done. If it is equal to 1, it means that the Do method has been called, return directly and Do nothing. Otherwise, the mutex is used to ensure the safety of the process to call the f function, and then the flag bit done is set to 1.
Let's take an example to implement a single instance:
package main import ( "fmt" "sync" "time" ) var once sync.Once var mmp map[int]string func main() { for i := 0; i < 10; i++ { go func(i int) { once.Do(func (){ mmp = make(map[int]string, 10) }) fmt.Printf("-----%d------%p\n", i, &mmp) }(i) } //Wait 1min for the main process and wait for the above 10 processes to be completed time.Sleep(1 * time.Second) }
We start 10 processes to compete for the mmp whose initialization type is dictionary type, and then print the address of each mmp. The operation output is as follows:
-----1------0x50cca0 -----3------0x50cca0 -----2------0x50cca0 -----4------0x50cca0 -----7------0x50cca0 -----6------0x50cca0 -----8------0x50cca0 -----9------0x50cca0 -----5------0x50cca0 -----0------0x50cca0 Process finished with exit code 0
We can see that the address of mmp is the same every time. This makes it easy and elegant to achieve the same effect as java singleton pattern.
Recommended articles:
This public account is free * * to provide csdn download service and massive it learning resources * * if you are ready to enter the IT pit and aspire to become an excellent program ape, these resources are suitable for you, including but not limited to java, go, python, springcloud, elk, embedded, big data, interview materials, front-end and other resources. At the same time, we have set up a technology exchange group. There are many big guys who will share technology articles from time to time. If you want to learn and improve together, you can reply [2] in the background of the public account. Free invitation plus technology exchange groups will learn from each other and share programming it related resources from time to time.
Scan the code to pay attention to the wonderful content and push it to you at the first time