0

0

如何在Golang中实现简单的爬虫限流_Golang channel与time控制方法

P粉602998670

P粉602998670

发布时间:2026-01-23 14:06:09

|

829人浏览过

|

来源于php中文网

原创

Go中限流最轻量可控方式是time.Ticker配合channel;固定频率限流用Ticker实现QPS控制,需注意信号积压问题;令牌桶限流则用带缓冲chan模拟burst和rate。

如何在golang中实现简单的爬虫限流_golang channel与time控制方法

Go 里实现爬虫限流,最轻量、最可控的方式就是用 time.Ticker 配合 channel 控制请求节奏,而不是依赖第三方库或复杂调度器。

time.Ticker 做固定频率限流

这是最直观的限流方式:每 N 毫秒放行一个请求。适用于目标站点允许稳定 QPS(比如 10 QPS → 每 100ms 一个请求)。

  • Ticker 是持续发送时间信号的 channel,比反复 time.Sleep 更精确、更易管理
  • 必须在 goroutine 中消费 Ticker.C,否则会阻塞;也别忘了 defer ticker.Stop()
  • 若请求处理耗时超过 tick 间隔,Ticker 会积压信号,导致“脉冲式”并发 —— 这不是你想要的限流,得加缓冲或改用 time.AfterFunc 方式
func main() {
    ticker := time.NewTicker(100 * time.Millisecond)
    defer ticker.Stop()
urls := []string{"https://example.com/1", "https://example.com/2", ...}

for _, url := range urls {
    <-ticker.C // 等待下一个时间点
    go func(u string) {
        resp, err := http.Get(u)
        if err != nil {
            log.Printf("failed to fetch %s: %v", u, err)
            return
        }
        defer resp.Body.Close()
    }(url)
}

// 注意:这里没等 goroutine 结束,实际需用 sync.WaitGroup

}

用带缓冲的 chan struct{} 实现令牌桶式限流

当需要支持突发流量(比如允许最多 5 个请求瞬间发出,之后限速为 10 QPS),纯 Ticker 不够用,得模拟令牌桶。核心是用带缓冲的 channel 当“令牌池”。

立即学习go语言免费学习笔记(深入)”;

Sora
Sora

Sora是OpenAI发布的一种文生视频AI大模型,可以根据文本指令创建现实和富有想象力的场景。

下载
  • 启动一个 goroutine 持续往 tokenCh 里塞令牌(struct{} 占 0 字节,最省)
  • 每次发请求前从 tokenCh 取一个令牌 —— 若缓冲已满,就阻塞等待;若取到就继续
  • 缓冲容量 = 最大并发数(burst),填充速率 = 1 / 间隔(rate)
  • 注意:不要用 len(tokenCh) 判断剩余令牌,因为并发下不准确;channel 本身已提供线程安全的计数语义
func newTokenBucket(burst int, rate time.Duration) <-chan struct{} {
    ch := make(chan struct{}, burst)
    go func() {
        ticker := time.NewTicker(rate)
        defer ticker.Stop()
        for range ticker.C {
            select {
            case ch <- struct{}{}:
            default:
            }
        }
    }()
    return ch
}

func main() { tokenCh := newTokenBucket(5, 100*time.Millisecond) // 允许最多 5 个并发,平均 10 QPS

for _, url := range urls {
    <-tokenCh // 拿令牌,阻塞直到有空位
    go func(u string) {
        defer func() { <-tokenCh }() // 请求结束归还?不,这里是单向发放,不回收
        http.Get(u)
    }(url)
}

}

为什么不用 time.Sleep 直接控制?

看似简单,但容易出错:

  • 在循环里写 time.Sleep(100 * time.Millisecond),如果某次 http.Get 耗时 500ms,那下一次请求就在 600ms 后才发 —— 实际 QPS 远低于预期
  • 无法应对失败重试:重试逻辑若插在 sleep 前后,会打乱节奏;插在中间又可能让重试挤占正常请求 slot
  • sleep 是 goroutine 级阻塞,而 Ticker + channel 是协作式控制,更利于组合(比如和 context.WithTimeout 一起用)

真实场景中容易忽略的关键点

限流只是爬虫健壮性的一环,真正上线时这几个细节常被跳过:

  • HTTP client 必须设 Timeout,否则一个卡住的请求会让整个限流 channel 堵死
  • 域名级限流比全局限流更重要:对不同 host 使用独立的 tokenCh,避免 A 站慢拖垮 B 站
  • http.DefaultClientTransport.MaxIdleConnsPerHost 默认是 2,高并发下会排队 —— 要调大,否则限流没意义
  • 别把限流逻辑和业务逻辑耦合在同一个 goroutine 里;推荐用“生产者-消费者”模式:一个 goroutine 按节奏发 URL 到任务 channel,另一组 worker 从 channel 消费并执行请求

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

180

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

340

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

393

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

191

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

273

2025.06.17

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号