golang,go,博客,开源,编程

认识semaphore

Published on with 0 views and 0 comments

golang.org/x/sync/semaphore 是 Go 语言中一个用于实现信号量的工具包,它提供了一个高效的信号量实现,用于控制并发访问的数量。信号量通常用于限制资源的并发访问,避免系统过载或者达到资源上限。Go 官方的 golang.org/x/sync/semaphore 包为开发者提供了一个可靠的方式来实现信号量控制。

安装

要使用 golang.org/x/sync/semaphore,首先需要通过以下命令安装该包:

go get golang.org/x/sync/semaphore

信号量(Semaphore)简介

信号量是一种控制资源访问的同步机制。它可以确保在同一时刻,最多只有指定数量的 Goroutine 能够访问共享资源。当信号量的计数器大于 0 时,Goroutine 可以获得信号量并访问资源。每当一个 Goroutine 完成资源操作时,它会释放信号量,允许其他 Goroutine 获取信号量。信号量通常用于限制并发的数量。

semaphore 包的主要功能

  • NewWeighted():创建一个具有指定权重的信号量实例,允许你设置最多同时允许多少 Goroutine 访问资源。
  • Acquire():请求信号量。如果信号量已用完,Goroutine 会被阻塞,直到信号量有空余资源。
  • Release():释放信号量,允许其他等待的 Goroutine 继续执行。

semaphore 示例

以下是一个使用 golang.org/x/sync/semaphore 来限制并发数的示例。我们将启动多个 Goroutine,每个 Goroutine 在执行时会请求信号量,执行完毕后释放信号量,从而控制并发数量。

package main

import (
	"fmt"
	"golang.org/x/sync/semaphore"
	"sync"
	"time"
)

func main() {
	// 创建一个信号量,最多允许 3 个 Goroutine 同时访问
	sem := semaphore.NewWeighted(3)

	var wg sync.WaitGroup

	// 启动 10 个 Goroutine
	for i := 1; i <= 10; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()

			// 请求信号量,如果信号量已用完,该 Goroutine 将会阻塞
			if err := sem.Acquire(nil, 1); err != nil {
				fmt.Printf("Goroutine %d failed to acquire semaphore: %v\n", id, err)
				return
			}

			// 模拟任务执行
			fmt.Printf("Goroutine %d is running\n", id)
			time.Sleep(2 * time.Second)
			fmt.Printf("Goroutine %d is done\n", id)

			// 释放信号量
			sem.Release(1)
		}(i)
	}

	// 等待所有 Goroutine 完成
	wg.Wait()
	fmt.Println("All tasks are completed!")
}

代码解析

  1. sem := semaphore.NewWeighted(3):创建一个信号量,最大容量为 3,表示最多允许 3 个 Goroutine 同时执行。
  2. sem.Acquire(nil, 1):每个 Goroutine 请求信号量。如果信号量的计数器为 0,则该 Goroutine 会阻塞,直到有其他 Goroutine 释放信号量。
  3. sem.Release(1):任务完成后,释放信号量,允许其他阻塞的 Goroutine 获得信号量继续执行。
  4. sync.WaitGroup:用于等待所有 Goroutine 完成。

重要方法

  • NewWeighted(n int64):创建一个新的加权信号量。n 是信号量的容量(最大允许的并发数)。
  • Acquire(ctx context.Context, n int64):请求信号量。如果信号量的剩余量不足,当前 Goroutine 会被阻塞,直到足够的信号量可用。n 参数表示要请求的信号量数量,ctx 用于支持取消操作(如果需要)。
  • Release(n int64):释放信号量,增加信号量的可用数量。

semaphore 与通道的对比

在 Go 中,信号量通常可以通过通道来实现。golang.org/x/sync/semaphore 提供了更高效、更灵活的实现,尤其是在需要控制并发数时。

特性semaphore通道实现的信号量
信号量容量控制
阻塞和释放机制自动处理需要手动实现
支持的并发数有灵活的权重控制通常基于缓冲通道大小
内存管理更高效可能需要手动优化

适用场景

  • 资源池:如果你有一个共享资源池(比如数据库连接池、缓存池等),可以使用信号量控制同时访问这些资源的 Goroutine 数量。
  • 限制并发:当你希望限制某个任务的并发执行数量时,信号量是一种非常有效的方式。
  • 流量控制:如果你需要对外部服务或 API 进行请求,并且希望限制并发请求数,信号量可以帮助你有效地控制并发。

总结

  • golang.org/x/sync/semaphore 提供了一个高效、简单的方式来管理并发任务,它可以控制同一时刻允许多少个 Goroutine 执行任务,适用于需要资源限制和并发控制的场景。
  • 使用信号量可以帮助防止资源过载,确保系统平稳运行,特别适用于数据库连接池、API 请求限流等场景。

标题:认识semaphore
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/01/07/1736232020863.html
联系:scotttu@163.com