The sync package

The sync package of Go's standard library provides additional synchronization features that aren't included in the language itself. Its additions to concurrency management include Mutex, WaitGroup, and Once, which we'll look at briefly.

Mutex is used when you want to ensure mutual exclusion—that is, if you only want one goroutine to access a piece of data at a time (to avoid potential conflicts). The key methods are Lock() and Unlock(), which surround the section of code that should never be executed concurrently. If a second goroutine attempts to enter the section, it will block until the lock is released:

var vals map[string]string
var lock sync.Mutex

func Get(key string) string {
lock.Lock()
defer lock.Unlock()
return vals[key]
}

func Set(key, value string) {
lock.Lock()
vals[key] = value
lock.Unlock()
}

In the preceding example, we have a map, vals, that we want to share and so must ensure thread-safety. We add sync.Mutex to guard the access and ensure that the lock is obtained before using the map. Note that in the Get method, we use the defer keyword to ensure the code is called as the method exits—this avoids needing to access the map, storing the value, and unlocking before then returning (making the code neater).

WaitGroup is helpful if you want to create a number of background activities and then wait until they all complete. For example, this code snippet creates a download method that takes an additional parameter for the group it's part of. Each download instance increments the group counter (Add(1)) at the start of the download and clears it (Done()) at the end. The calling function sets up a wait group and then calls Wait(), which will return once all downloads are complete:

func Download(url string, group *sync.WaitGroup) {
group.Add(1)
http.Get(url)
group.Done()
}

func main() {
...
var group sync.WaitGroup
go download("http://example.com/image1.png", group)
go download("http://example.com/image2.png", group)
group.Wait()
fmt.Println("Done")
...
}

The last example, Once, is rather self-explanatory—it allows code to be executed once only. Invoking its Do(func()) method will cause the passed function to never be called more than once. This is helpful if you're trying to implement a lazy-loading singleton pattern, such as the following code:

var instance *myStruct
var once sync.Once

func GetInstance() *myStruct {
once.Do(func() {
instance = &myStruct{}
})

return instance
}

The full documentation is available at https://golang.org/pkg/sync/; however, it's recommended to use the channel constructs when possible, instead of most of these features.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.60.158