Skip to content

once

sync.Once adalah salah satu alat sinkronisasi di pustaka standar Go, digunakan untuk memastikan fungsi tertentu hanya dieksekusi sekali dalam lingkungan konkuren. Ini biasanya digunakan dalam skenario seperti lazy initialization, initialization sumber daya global, dll, memastikan operasi tertentu hanya akan dieksekusi sekali, bahkan jika ada beberapa goroutine yang mengeksekusi secara konkuren.

go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	var once sync.Once
	for i := range 10 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			once.Do(func() {
				fmt.Println(i)
			})
		}()
	}
	wg.Wait()
}

Dalam kode di atas, total ada 10 goroutine, tetapi bagaimanapun, hanya satu goroutine yang akan mengeksekusi fmt.Println(i) di dalam once.Do(). Goroutine mana yang akan mencetak, tergantung pada goroutine mana yang pertama kali mencapai once.Do().

Struktur

go
type Once struct {
    done atomic.Uint32
    m    Mutex
}

Struktur internalnya sangat sederhana

  1. done, sebuah nilai atomik, digunakan untuk menunjukkan apakah sudah dieksekusi
  2. m, mutex eksklusif, digunakan untuk阻塞 goroutine lain yang ingin mengeksekusi

Prinsipnya adalah mengunci sebelum eksekusi, kemudian memperbarui done, setelah eksekusi selesai membuka lock.

Do

go
func (o *Once) Do(f func()) {
	if o.done.Load() == 0 {
		o.doSlow(f)
	}
}

func (o *Once) doSlow(f func()) {
	o.m.Lock()
	defer o.m.Unlock()
	if o.done.Load() == 0 {
		defer o.done.Store(1)
		f()
	}
}

Kode secara keseluruhan sangat sederhana, alurnya adalah sebagai berikut:

  1. Langsung load nilai atomik, jika sudah dieksekusi langsung return
  2. Jika belum dieksekusi, coba pegang lock, di sini mungkin ada beberapa goroutine yang bersaing untuk mutex eksklusif
  3. Ketika pemenang berhasil memegang lock, masih perlu判断 nilai done sekali lagi, karena setelah Anda memegang lock, orang lain mungkin sudah menyelesaikan lock-eksekusi-unlock, saat ini Anda baru saja dibangunkan.
  4. Eksekusi fungsi target
  5. Perbarui nilai done
  6. Lepaskan lock

Ringkasan

sync.Once adalah alat sinkronisasi yang sangat ringkas dan efisien, memastikan operasi tertentu hanya dieksekusi sekali dalam lingkungan konkuren, sehingga menghindari pekerjaan berulang atau pemborosan sumber daya.

Golang by www.golangdev.cn edit