
本文介绍使用 goroutine 和 channel 实现高并发 http 请求的完整方案,解决 1500+ url 批量探测耗时过长的问题,将执行时间从 16 分钟大幅缩短,并提供可复用、可配置范围的并发函数。
本文介绍使用 goroutine 和 channel 实现高并发 http 请求的完整方案,解决 1500+ url 批量探测耗时过长的问题,将执行时间从 16 分钟大幅缩短,并提供可复用、可配置范围的并发函数。
在 Go 中实现 HTTP 请求的并发处理,核心在于合理利用 goroutine(轻量级协程)与 channel(安全通信管道),避免阻塞、竞争和资源耗尽。原始代码存在多个典型问题:全局变量 i 被多个 goroutine 共享导致竞态;未限制并发数引发连接风暴;channel 读写未做同步控制,threadPrint 会无限阻塞;且缺乏错误处理与超时机制。
以下是一个生产就绪的改进方案,封装为通用函数 getBusPostStatus(start, end int),支持任意 ID 区间并发探测,并内置连接复用、超时控制与错误抑制:
package main
import (
"fmt"
"net/http"
"time"
)
// 自定义 HTTP 客户端,设置超时防止请求挂起
var client = &http.Client{
Timeout: 5 * time.Second,
}
// getBusPostStatus 并发探测指定编号区间的公交站牌 URL 状态
// start(含)到 end(不含),例如 getBusPostStatus(600, 800) 探测 600~799 共 200 个站点
func getBusPostStatus(start, end int) total {
end = total
}
resultChannels = append(resultChannels, getBusPostStatus(start, end))
}
// 按批次接收并打印结果(也可统一收集后排序输出)
for _, ch := range resultChannels {
for j := 0; j <p><strong>关键优化说明:</strong> </p>
- ✅ 无竞态安全:每个 goroutine 使用独立参数
id,避免共享变量i; - ✅ 可控并发:通过
batchSize间接限流(如需严格限制并发数,可用semaphore或 worker pool 模式); - ✅ 健壮性增强:
http.Client设置Timeout,显式Close()响应体,错误分类输出; - ✅ 内存友好:使用带缓冲 channel(容量 = 批次大小),避免 goroutine 因发送阻塞而堆积;
- ✅ 灵活复用:
getBusPostStatus(start, end)可直接调用,如go getBusPostStatus(600, 800);
⚠️ 注意事项:
- 目标服务器可能对高频请求返回
429 Too Many Requests,建议添加time.Sleep()(如每 10 请求休眠 100ms)或使用rate.Limiter; - 生产环境应启用
http.Transport连接池(默认已启用),并根据需要调优MaxIdleConns等参数; - 若需结构化结果(如统计 OK/WARN 数量),可将
stringchannel 替换为自定义 struct channel(如chan struct{ID int; Status string; Code int})。
通过以上设计,1500 次请求通常可在数秒至一分钟内完成(取决于网络与服务端响应),真正发挥 Go 并发模型的高效优势。










