Sling Academy
Home/Golang/The Power of `sync.Once` for One-Time Initialization in Go

The Power of `sync.Once` for One-Time Initialization in Go

Last updated: November 27, 2024

When writing concurrent programs in Go, one common challenge developers face is ensuring that certain initialization tasks only happen once. sync.Once from Go's standard library is a powerful tool for addressing this challenge. It ensures that a piece of code is executed only once, even if it's being called from multiple goroutines.

Understanding sync.Once

The sync.Once type provides a method called Do. This method is responsible for ensuring that a specified function is executed just once throughout the lifetime of the program, regardless of how many times Do is called or from how many goroutines it is invoked.

Example of Using sync.Once

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initialize() {
    fmt.Println("Initialization function executed")
}

func main() {
    for i := 0; i < 3; i++ {
        go func(i int) {
            once.Do(initialize)
            fmt.Printf("Goroutine %d finished\n", i)
        }(i)
    }

    // Wait for user input to prevent program from exiting early
    fmt.Scanln()
}

In the example above, the initialize function will only print "Initialization function executed" once, even though the surrounding loop causes once.Do(initialize) to be called three times in separate goroutines. This guarantees that the initialization code runs exactly once in a concurrent setting, protecting the shared resource initialization.

Key Properties of sync.Once

  • Thread-Safe: sync.Once can be safely used by multiple goroutines, which eliminates the need for additional synchronization.
  • No Re-init: Once the function is executed, no further calls to Do will execute it again. Repeated calls to Do will have no effect.
  • Blocking: If multiple goroutines simultaneously invoke Do, only one will run the function, and the others will block until the function has returned.

Applications of sync.Once

sync.Once is commonly used for:

  • Singleton Pattern: Guaranteeing that a particular piece of initialization code is executed only once.
  • Resource Initialization: Such as opening a network connection, initializing a library, or loading a configuration file.
  • JavaScript and Golang Interoping: Efficiently bridging between multiple languages by making a certain function call or data load occur once.

Considerations When Using sync.Once

Be mindful that:

  • If the function passed to Do panics, the state of sync.Once becomes permanent. That means Do won't be retried unless you explicitly handle panics within the initialization function.
  • Ensuring that sync.Once is appropriate for the task is crucial, as it's strictly for guaranteeing a one-time execution with implicit lock handling.

Understanding and employing sync.Once effectively can simplify concurrent program design, leading to safer execution patterns and remaining vigilant against inadvertent resource re-initialization.

Next Article: Using Goroutines for Parallel File Processing in Go

Previous Article: Context in Go: Managing Timeouts and Cancellations

Series: Concurrency and Synchronization in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant