Introduction
The primary mission of Golang is to simplify asynchronous programming. When faced with operations requiring batch processing and lengthy execution times, traditional single-threaded execution becomes cumbersome, prompting the need for asynchronous parallel processing. This article introduces some tips for asynchronous programming in Golang.
This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on Medium. Thank you very much.
sourcegraph/conc
Let’s start by introducing a library that simplifies concurrent programming: conc
. It encapsulates many useful tools, such as WaitGroup
and iter.Map
. While we may not necessarily use conc
in production code, learning from its concepts is still beneficial.
Usage
Using go
The simplest and most common method: use the go
keyword.
|
|
Or:
|
|
Using anonymous functions to pass parameters:
|
|
This method doesn’t require consideration of return values. If return values are needed, the following method can be used.
Implementing Timeout Control with Goroutines and Channels
|
|
Using sync.WaitGroup
sync.WaitGroup
is used to wait for a collection of goroutines to finish their tasks. The Add()
method increases the number of goroutines to wait for, the Done()
method marks a goroutine as completed, and the Wait()
method blocks until all goroutines are finished.
|
|
Error Handling with errgroup
for Goroutine Groups
The errgroup
package is useful for easily capturing errors from goroutines. It’s a utility in the Go standard library for managing a group of goroutines and handling their errors.
|
|
Tips and Techniques
Using Range and Close Operations with Channels
The range can be used to iterate over the values received on a channel until the channel is closed. Use the close
function to close the channel, signaling no more values will be sent.
|
|
Waiting Multiple Goroutines With Select
|
|
Implementing Timeout Control with Select and time.After()
If you need to set a timeout for asynchronous operations, you can use the select statement in conjunction with the time.After()
function.
|
|
Using time.Tick()
and time.After()
for Timed Operations
The time.Tick()
function returns a channel that sends time values periodically, useful for executing timed operations. The time.After()
function returns a channel that sends a time value after a specified duration.
|
|
Using sync.Mutex
or sync.RWMutex
for Concurrent Safe Access
When multiple goroutines concurrently access shared data, it’s essential to ensure data access safety. sync.Mutex
and sync.RWMutex
provide mutual exclusion locks and read-write locks for locking before accessing shared resources, preventing data races.
|
|
Note: sync.Mutex
locks cannot be nested. sync.RWMutex
read locks (RLock()
) can be nested if there are no write locks, and multiple read locks can be acquired.
Using sync.Cond
for Conditional Variable Control
sync.Cond
is a conditional variable used for communication and synchronization between goroutines. It can block and wait until a specified condition is met, then wake up waiting goroutines when the condition is satisfied.
|
|
Managing Object Pools with sync.Pool
sync.Pool
is an object pool for caching and reusing temporary objects, improving allocation and recycling efficiency.
|
|
Ensuring One-Time Execution with sync.Once
sync.Once
ensures that an operation is executed only once, regardless of how many goroutines attempt to execute it. It’s commonly used for initialization or loading resources.
|
|
Resource Cleanup with sync.Once
and context.Context
Combine sync.Once
and context.Context
to ensure a resource cleanup operation is executed only once across multiple goroutines, triggered on cancellation or timeout.
|
|
Concurrent Safe Maps with sync.Map
sync.Map
is a concurrent-safe map type in the
Go standard library, enabling safe read and write operations across multiple goroutines.
|
|
Managing Goroutines and Cancellation with context.Context
context.Context
is used to pass context information between goroutines and can be used for cancellation or timeout control. Use context.WithCancel()
to create a cancellable context, and context.WithTimeout()
to create a context with a timeout.
|
|
Setting Deadlines with context.WithDeadline()
and context.WithTimeout()
context.WithDeadline()
and context.WithTimeout()
functions create contexts with deadlines to limit the execution time of asynchronous tasks.
|
|
Passing Context Values with context.WithValue()
context.WithValue()
allows passing key-value pairs within a context, enabling sharing and passing context-related values between goroutines.
|
|
Atomic Operations with the atomic
Package
The atomic
package provides functions for atomic operations, ensuring atomicity in read and write operations on shared variables in concurrent environments.
|
|
Summary
In this article, we introduce some commonly used keywords. Mastering these keywords will make it easy to deal with common concurrent programming. I believe you have also discovered that the go source code does not provide the commonly used Barrier
function in java
and c#
. Although we can also implement the Barrier
function using basic concurrent statements, it is not as convenient as calling the ready-made API interface. There is SingleFlight
in golang.org/x
and the third-party CyclicBarrier
. In the next article, we will introduce these two concurrent primitives.