Go Concurrency: Mutexes vs Channels with Examples
Counter synchronization in Go concurrent programming: Mutex, buffered channels and unbuffered channels
When building concurrent applications in Go, synchronization is crucial to ensure secure access to shared data. Mutex
and Channel
are the main tools for synchronization in Go.
This article explores several ways to build safe concurrency counters. While the reference article solves this problem using Mutex
, we'll also explore alternatives using buffered and unbuffered channels.
Problem Description
We need to build a counter that can be safely used concurrently.
Counter code
package main type Counter struct { count int } func (c *Counter) Inc() { c.count++ } func (c *Counter) Value() int { return c.count }
To make our code concurrency safe, let’s write some tests.
1. Use Mutex
Mutex
(mutex) is a synchronization primitive that ensures that only one goroutine can access critical parts of the code at a time. It provides a locking mechanism: when a goroutine locks Mutex
, other goroutines trying to lock it will be blocked until Mutex
is unlocked. Therefore, it is often used when a shared variable or resource needs to be protected from race conditions.
package main import ( "sync" "testing" ) func TestCounter(t *testing.T) { t.Run("using mutexes and wait groups", func(t *testing.T) { counter := Counter{} wantedCount := 1000 var wg sync.WaitGroup var mut sync.Mutex wg.Add(wantedCount) for i := 0; i < wantedCount; i++ { go func() { defer wg.Done() mut.Lock() counter.Inc() mut.Unlock() }() } wg.Wait() if counter.Value() != wantedCount { t.Errorf("got %d, want %d", counter.Value(), wantedCount) } }) }
The code uses sync.WaitGroup
to track the completion of all goroutines, and uses sync.Mutex
to prevent multiple goroutines from accessing the shared counter at the same time.
2. Use buffer channel
Channels are a way for Go to allow goroutines to communicate securely. They are able to transfer data between goroutines and provide synchronization by controlling access to the passed data.
In this example, we will use channels to block goroutines and allow only one goroutine to access the shared data. Buffered channels have a fixed capacity, meaning they can hold a predefined number of elements before blocking the sender. The sender will only block when the buffer is full.
package main import ( "sync" "testing" ) func TestCounter(t *testing.T) { t.Run("using buffered channels and wait groups", func(t *testing.T) { counter := Counter{} wantedCount := 1000 var wg sync.WaitGroup wg.Add(wantedCount) ch := make(chan struct{}, 1) ch <- struct{}{} // 允许第一个 goroutine 开始 for i := 0; i < wantedCount; i++ { go func() { defer wg.Done() <-ch counter.Inc() ch <- struct{}{} }() } wg.Wait() if counter.Value() != wantedCount { t.Errorf("got %d, want %d", counter.Value(), wantedCount) } }) }
The code uses a buffered channel with a capacity of 1, allowing only one goroutine to access the counter at a time.
3. Use non-buffered channels
Unbuffered channels have no buffers. They block the sender until the receiver is ready to receive data. This provides strict synchronization, where data is passed between goroutines one at a time.
package main import ( "sync" "testing" ) func TestCounter(t *testing.T) { t.Run("using unbuffered channels and wait groups", func(t *testing.T) { counter := Counter{} wantedCount := 1000 var wg sync.WaitGroup wg.Add(wantedCount) ch := make(chan struct{}) go func() { for i := 0; i < wantedCount; i++ { ch <- struct{}{} } close(ch) }() for range ch { counter.Inc() wg.Done() } if counter.Value() != wantedCount { t.Errorf("got %d, want %d", counter.Value(), wantedCount) } }) }
The code uses unbuffered channels to ensure that only one goroutine accesses the counter at a time.
4. Use buffer channel instead of WaitGroup
We can also use buffered channels without WaitGroup
, for example using an infinite loop or another channel to track the completion of the goroutine.
Conclusion
This article explores different approaches to building safe concurrency counters in Go. Knowing these tools and when to use them is key to writing efficient and safe concurrent Go programs.
Reference Resources
This article is inspired by the synchronization chapter in "Learn Go with tests".
Hope this article is helpful to you!
The above is the detailed content of Go Concurrency: Mutexes vs Channels with Examples. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

OpenSSL, as an open source library widely used in secure communications, provides encryption algorithms, keys and certificate management functions. However, there are some known security vulnerabilities in its historical version, some of which are extremely harmful. This article will focus on common vulnerabilities and response measures for OpenSSL in Debian systems. DebianOpenSSL known vulnerabilities: OpenSSL has experienced several serious vulnerabilities, such as: Heart Bleeding Vulnerability (CVE-2014-0160): This vulnerability affects OpenSSL 1.0.1 to 1.0.1f and 1.0.2 to 1.0.2 beta versions. An attacker can use this vulnerability to unauthorized read sensitive information on the server, including encryption keys, etc.

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

This article introduces a variety of methods and tools to monitor PostgreSQL databases under the Debian system, helping you to fully grasp database performance monitoring. 1. Use PostgreSQL to build-in monitoring view PostgreSQL itself provides multiple views for monitoring database activities: pg_stat_activity: displays database activities in real time, including connections, queries, transactions and other information. pg_stat_replication: Monitors replication status, especially suitable for stream replication clusters. pg_stat_database: Provides database statistics, such as database size, transaction commit/rollback times and other key indicators. 2. Use log analysis tool pgBadg

Under the BeegoORM framework, how to specify the database associated with the model? Many Beego projects require multiple databases to be operated simultaneously. When using Beego...

The problem of using RedisStream to implement message queues in Go language is using Go language and Redis...
