Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go 并发控制利器 ants

Go 并发控制利器 ants 使用方法与实践

作者:言之。

ants是一个高效的Go语言goroutine池实现,通过复用已完成任务的goroutine来减少资源开销并限制并发数量,本文就来详细的介绍一下Go 并发控制利器 ants的使用,感兴趣的可以了解一下

1.ants基础应用

https://github.com/panjf2000/ants

1.1 什么是ants

ants 是一个高性能的 Go 语言 goroutine 池,它能复用已完成任务的 goroutine,避免频繁创建和销毁 goroutine,节省 CPU 与内存开销,并且能限制并发数量防止资源被耗尽。

1.2 安装

go get -u github.com/panjf2000/ants/v2

1.3 最简单的例子

package main

import (
	"fmt"
	"time"

	"github.com/panjf2000/ants/v2"
)

func main() {
	// 创建一个容量为 10 的 goroutine 池
	pool, _ := ants.NewPool(10)
	defer pool.Release() // 程序结束释放资源

	// 提交任务
	for i := 0; i < 20; i++ {
		n := i
		_ = pool.Submit(func() {
			fmt.Printf("Task %d running\n", n)
			time.Sleep(time.Second)
		})
	}

	fmt.Println("All tasks submitted")
	time.Sleep(3 * time.Second) // 等待任务执行完
}

特点:

2. 进阶篇

2.1 核心 API

方法作用
ants.NewPool(size, options...)创建一个普通任务池
ants.NewPoolWithFunc(size, func, options...)创建一个绑定任务处理函数的池
Submit(task)提交任务到池
Invoke(param)提交参数,调用绑定函数
Running()当前正在运行的 worker 数量
Free()当前空闲 worker 数量
Cap()池容量
Tune(size)动态调整容量
Release()释放所有资源
Reboot()重启一个已释放的池

2.2 常用配置项

ants.WithPreAlloc(true)           // 预先分配内存,减少运行时分配
ants.WithNonblocking(true)        // worker 不够时立即返回错误,而不是等待
ants.WithMaxBlockingTasks(1000)   // 最大等待任务数
ants.WithPanicHandler(func(err interface{}) {
	fmt.Println("panic:", err)     // 捕获任务中的 panic
})
ants.WithExpiryDuration(time.Second * 10) // 空闲 worker 过期时间

2.3PoolWithFunc用法

package main

import (
	"fmt"
	"github.com/panjf2000/ants/v2"
	"time"
)

func main() {
	// 定义处理函数
	handler := func(data interface{}) {
		fmt.Printf("Processing: %v\n", data)
		time.Sleep(time.Millisecond * 500)
	}

	// 创建绑定函数的池
	pool, _ := ants.NewPoolWithFunc(5, handler)
	defer pool.Release()

	for i := 0; i < 10; i++ {
		_ = pool.Invoke(i) // 直接传参数
	}
}

3. 实战篇

3.1 批量任务执行

场景:你需要批量处理 10000 条数据,但不希望一次性开 10000 个 goroutine。

package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/panjf2000/ants/v2"
)

func processTask(id int) {
	fmt.Printf("Task %d start\n", id)
	time.Sleep(time.Second)
	fmt.Printf("Task %d done\n", id)
}

func main() {
	var wg sync.WaitGroup
	pool, _ := ants.NewPool(50) // 控制并发为 50
	defer pool.Release()

	for i := 0; i < 10000; i++ {
		wg.Add(1)
		taskID := i
		_ = pool.Submit(func() {
			defer wg.Done()
			processTask(taskID)
		})
	}
	wg.Wait()
}

3.2 HTTP 并发控制

爬取多个 URL,但限制同时请求的数量。

package main

import (
	"fmt"
	"net/http"
	"sync"

	"github.com/panjf2000/ants/v2"
)

func fetch(url string) {
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	fmt.Println(url, resp.StatusCode)
}

func main() {
	urls := []string{
		"https://golang.org",
		"https://github.com",
		"https://google.com",
	}

	var wg sync.WaitGroup
	pool, _ := ants.NewPool(5)
	defer pool.Release()

	for _, url := range urls {
		wg.Add(1)
		u := url
		_ = pool.Submit(func() {
			defer wg.Done()
			fetch(u)
		})
	}

	wg.Wait()
}

4. 最佳实践与注意事项

  1. 适合长时间运行的服务

    • 在任务密集的服务中能显著降低内存占用。
  2. 任务不宜过大或阻塞太久

    • 单个任务阻塞会占用 worker,影响吞吐量。
  3. panic 处理必须配置

    • 避免单个任务导致池崩溃。
  4. 选择合适的池大小

    • 一般为 CPU核数 * N,N 根据 IO 密集度调整。
  5. 性能对比

    • 对于少量任务,直接开 goroutine 可能更快;
    • 对于大规模并发,ants 会明显减少 GC 压力。

到此这篇关于Go 并发控制利器 ants 使用文档的文章就介绍到这了,更多相关Go 并发控制利器 ants内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文