> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Golang High-Performance Programming EP6: Tips For Asynchronous Programming
- URL: https://huizhou92.com/golang-high-performance-programming-ep6-tips-for-asynchronous-programming-2/
- Published: 2024-07-23T15:46:27.000Z
- Updated: 2026-09-08T02:31:01.000Z
- Description: Golang High-Performance Programming EP6: Tips For Asynchronous Programming. Introduction The primary mission of Golang is to simplify asynchronous programm。
- Author: huizhou92
- Tags: #Migrated-1788833207488, #Import 2026-09-08 02:07

### 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.

### [sourcegraph/conc](https://github.com/sourcegraph/conc?ref=huizhou92.com)

Let’s start by introducing a library that simplifies concurrent programming: `conc`. It encapsulates many useful tools, such as [WaitGroup](https://pkg.go.dev/github.com/sourcegraph/conc?ref=huizhou92.com#WaitGroup) and [iter.Map](https://pkg.go.dev/github.com/sourcegraph/conc/iter?ref=huizhou92.com#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 is to use the `go` keyword.

```go
func main() {   
  go func() {   
   fmt.Println("hello world1")   
  }()   
  go func() {   
   fmt.Println("hello world2")   
  }()   
 }
```

Or:

```go
func main() {   
  go Announce("hello world1")   
  go Announce("hello world2")   
 }   
 func Announce(message string) {   
  fmt.Println(message)   
 }
```

Using anonymous functions to pass parameters:

```go
data := "Hello, World!"   
 go func(msg string) {   
  // Use msg to perform asynchronous task logic processing 
  fmt.Println(msg)   
 }(data)
```

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

```go
ch := make(chan int, 1)   
 timer := time.NewTimer(time.Second)   
 go func() {   
     time.Sleep(2 * time.Second)   
     ch <- 1   
     close(ch)   
 }()   
 select {   
 case <-timer.C:   
     fmt.Println("timeout")   
 case result := <-ch:   
     fmt.Println(result)   
 }
```

#### 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.

```go
var wg sync.WaitGroup   
 // Start multiple goroutines   
 for i := 0; i < 5; i++ {   
    wg.Add(1)   
    go func(index int) {   
       defer wg.Done()   
       // Asynchronous task logic   
    }(i)   
 }   
 wg.Wait()
```

#### 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.

```go
var eg errgroup.Group   
 for i := 0; i < 5; i++ {   
     eg.Go(func() error {   
      return errors.New("error")   
     })   
 ​ 
     eg.Go(func() error {   
      return nil   
     })   
 }   
 ​ 
 if err := eg.Wait(); err != nil {   
     // Handle error   
 }
```

### 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.

```go
ch := make(chan int)   
 ​ 
 go func() {   
     for i := 0; i < 5; i++ {   
         ch <- i // Send values to the channel   
     }   
     close(ch) // Close the channel   
 }()   
 ​ 
 // Use range to iterate over received values 
 for val := range ch {   
     // Process received values   
 }
```

#### Waiting for Multiple Goroutines With Select

```go
ch1 := make(chan int)   
 ch2 := make(chan string)   
 ​ 
 go func() {   
     // Asynchronous task 1 logic   
     ch1 <- result1   
 }()   
 ​ 
 go func() {   
     // Asynchronous task 2 logic   
     ch2 <- result2   
 }()   
 ​ 
 // Wait for multiple asynchronous tasks to complete in the main goroutine 
 select {   
 case res1 := <-ch1:   
     // Process result 1   
 case res2 := <-ch2:   
     // Process result 2   
 }
```

#### 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.

```go
ch := make(chan int)   
 ​ 
 go func() {   
     // Asynchronous task logic   
     time.Sleep(2 * time.Second)   
     ch <- result   
 }()   
 ​ 
 // Set a timeout 
 select {   
 case res := <-ch:   
     // Process result   
 case <-time.After(3 * time.Second):   
     // Handle timeout   
 }
```

#### Using `time.Tick()` and `time.After()` for Timed Operations

The `time.Tick()` function returns a channel that sends time values periodically, which is useful for executing timed operations. The `time.After()` function returns a channel that sends a time value after a specified duration.

```go
tick := time.Tick(1 * time.Second) // Execute an operation every second   
 ​ 
 for {   
     select {   
     case <-tick:   
         // Perform timed operation   
     }   
 }   
 ​ 
 select {   
 case <-time.After(5 * time.Second):   
     // Execute operation after 5 seconds   
 }
```

#### Using `sync.Mutex` or `sync.RWMutex` for Concurrent Safe Access

When multiple goroutines concurrently access shared data, ensuring data access safety is essential. `sync.Mutex` and `sync.RWMutex` provide mutual exclusion and read-write locks for locking before accessing shared resources, preventing data races.

```go
var mutex sync.Mutex   
 var data int   
 ​ 
 // Write operation protected by a mutex 
 mutex.Lock()   
 data = 123   
 mutex.Unlock()   
 ​ 
 // Read operation protected by a read lock 
 mutex.RLock()   
 value := data   
 mutex.RUnlock()   
 ​ 
 var rwMutex sync.RWMutex   
 var sharedData map[string]string   
 ​ 
 // Read operation protected by a read lock 
 func readData(key string) string {   
     rwMutex.RLock()   
     defer rwMutex.RUnlock()   
     return sharedData[key]   
 }   
 ​ 
 // Write operation protected by a write lock 
 func writeData(key, value string) {   
     rwMutex.Lock()   
     defer rwMutex.Unlock()   
     sharedData[key] = value   
 }
```

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 until the condition is satisfied.

```go
var cond = sync.NewCond(&sync.Mutex{})   
 var ready bool   
 ​ 
 go func() {   
     // Asynchronous task logic   
     ready = true   
 ​ 
     // Notify waiting goroutines that the condition is met 
     cond.Broadcast()   
 }()   
 ​ 
 // Wait for the condition to be met 
 cond.L.Lock()   
 for !ready {   
     cond.Wait()   
 }   
 cond.L.Unlock()
```

#### Managing Object Pools With `sync.Pool`

`sync.Pool` is an object pool for caching and reusing temporary objects, improving allocation and recycling efficiency.

```go
type MyObject struct {   
     // Object structure   
 }   
 ​ 
 var objectPool = sync.Pool{   
     New: func() interface{} {   
         // Create a new object   
         return &MyObject{}   
     },   
 }   
 ​ 
 // Get an object from the pool 
 obj := objectPool.Get().(*MyObject)   
 ​ 
 // Use the object   
 ​ 
 // Put the object back into the pool 
 objectPool.Put(obj)
```

#### 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.

```go
var once sync.Once   
 var resource *Resource   
 ​ 
 func getResource() *Resource {   
     once.Do(func() {   
         // Perform resource initialization, executed only once 
         resource = initResource()   
     })   
     return resource   
 }   
 ​ 
 // Get the resource in multiple goroutines 
 go func() {   
     res := getResource()   
     // Use the resource   
 }()   
 ​ 
 go func() {   
     res := getResource()   
     // Use the resource   
 }()
```

#### 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.

```go
var once sync.Once   
 ​ 
 func cleanup() {   
     // Perform resource cleanup   
 }   
 ​ 
 func doTask(ctx context.Context) {   
     go func() {   
         select {   
         case <-ctx.Done():   
             once.Do(cleanup) // Execute resource cleanup only once 
         }   
     }()   
 ​ 
     // Asynchronous task logic 
 }
```

#### 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.

```dart
var m sync.Map   
 ​ 
 // Store key-value pairs 
 m.Store("key", "value")   
 ​ 
 // Retrieve values 
 if val, ok := m.Load("key"); ok {   
     // Use the value   
 }   
 ​ 
 // Delete a key 
 m.Delete("key")
```

#### 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.

```go
ctx, cancel := context.WithCancel(context.Background())   
 ​ 
 go func() {   
     // Asynchronous task logic   
     if someCondition {   
         cancel() // Cancel the task   
     }   
 }()   
 ​ 
 // Wait for the task to complete or be canceled 
 select {   
 case <-ctx.Done():   
     // Task canceled or timed out   
 }
```

#### 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.

```go
func doTask(ctx context.Context) {   
     // Asynchronous task logic   
 ​ 
     select {   
     case <-time.After(5 * time.Second):   
         // Handle timeout   
     case <-ctx.Done():   
         // Handle context cancellation   
     }   
 }   
 ​ 
 func main() {   
     ctx := context.Background()   
     ctx, cancel := context.WithTimeout(ctx, 3*time.Second)   
     defer cancel()   
 ​ 
     go doTask(ctx)   
 ​ 
     // Continue with other operations   
 }
```

#### 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.

```go
type keyContextValue string   
 ​ 
 func doTask(ctx context.Context) {   
     if val := ctx.Value(keyContextValue("key")); val != nil {   
         // Use the context value   
     }   
 }   
 ​ 
 func main() {   
     ctx := context.WithValue(context.Background(), keyContextValue("key"), "value")   
     go doTask(ctx)   
 ​ 
     // Continue with other operations   
 }
```

#### 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.

```go
var counter int64 
 ​ 
 func increment() { 
     atomic.AddInt64(&counter, 1) 
 } 
 ​ 
 func main() { 
     var wg sync.WaitGroup 
     for i := 0; i < 100; i++ { 
         wg.Add(1) 
         go func() { 
             defer wg.Done() 
             increment() 
         }() 
     } 
     wg.Wait() 
     fmt.Println("Counter:", counter) 
 }
```

### 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. In fact, there is `SingleFlight` in `golang.org/x` and the third-party [CyclicBarrier](http://In%20this%20article,%20we%20introduce%20some%20commonly%20used%20keywords.%20Mastering%20these%20keywords%20will%20make%20it%20easy%20to%20deal%20with%20common%20concurrent%20programming.%20I%20believe%20you%20have%20also%20discovered%20that%20the%20go%20source%20code%20does%20not%20provide%20the%20commonly%20used%20`Barrier`%20function%20in%20`java`%20and%20`c#`.%20Although%20we%20can%20also%20implement%20the%20`Barrier`%20function%20using%20basic%20concurrent%20statements,%20it%20is%20not%20as%20convenient%20as%20calling%20the%20ready-made%20API%20interface.%20In%20fact,%20there%20is%20`SingleFlight`%20in%20`golang.org/x`%20and%20the%20third-party%20`CyclicBarrier`.%20In%20the%20next%20article,%20we%20will%20introduce%20these%20two%20concurrent%20primitives.). In the next article, we will introduce these two concurrent primitives.

[文章索引](/article-index/)