Skip to content

once

sync.Once Go'nun standart kütüphanesinde bir senkronizasyon aracıdır, eşzamanlı ortamda bir fonksiyonun sadece bir kez yürütülmesini sağlamak için kullanılır. Tembel başlatma, global kaynak başlatma vb. senaryolarda yaygın olarak kullanılır, belirli bir işlemin sadece bir kez yürütülmesini garanti eder, birden fazla goroutine eşzamanlı olarak yürütülse bile.

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()
}

Yukarıdaki kodda, toplam 10 goroutine vardır, ancak her ne olursa olsun, sadece bir goroutine once.Do() içinde fmt.Println(i) yürütecektir. Hangi goroutine'in yazdıracağı hangi goroutine'in once.Do()'a ilk ulaştığına bağlıdır.

Yapı

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

İç yapısı çok basittir:

  1. done, yürütülüp yürütülmediğini belirtmek için kullanılan bir atomik değer
  2. m, yürütmek isteyen diğer goroutine'leri engellemek için kullanılan mutex kilidi

Prensibi yürütmeden önce kilitlemek, sonra done'u güncellemek ve yürütme tamamlandıktan sonra kilidi açmaktır.

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()
	}
}

Kod genel olarak çok basittir, akış şöyledir:

  1. Atomik değeri doğrudan yükle, eğer zaten yürütüldüyse, hemen dön
  2. Eğer yürütülmediyse, kilidi almaya çalış, burada birden fazla goroutine mutex için yarışıyor olabilir
  3. Kazanan kilidi başarıyla aldıktan sonra, hala done değerini tekrar kontrol etmelidir, çünkü kilidi aldıktan sonra, başkası zaten kilit-al-yürüt-kilit-aç dizisini tamamlamış olabilir ve siz yeni uyandırıldınız.
  4. Hedef fonksiyonu yürüt
  5. done değerini güncelle
  6. Kilidi serbest bırak

Özet

sync.Once çok öz ve verimli bir senkronizasyon aracıdır. Eşzamanlı ortamda belirli bir işlemin sadece bir kez yürütülmesini garanti eder, böylece tekrarlanan iş veya kaynak israfını önler.

Golang by www.golangdev.cn edit