Go 外部 API 接口的固定并发请求

前段时间,在一家公司呆了 20 多天,他们有个业务,需要定时更新业务的数据,更新的流程大概是,请求外部接口然后自行转换一下然后上报到百度那边。

但他们原本的处理和我写的补偿发放简易版不太一样,他们弄了个 HTML 来循环请求自己的接口,处理是同步的,并发是 1,所以有时候需要开几个电脑,然后每个电脑又是开几个浏览器,这样子一直来访问,相当于效率还是很低的,而且别人电脑也会占用到,影响了别人的工作进度。

当然,我已经离职很久了,这只是对之前的方案进行一个优化,不进行大的调整这是很重要的,毕竟很多人的业务也已经是屎山了。

大概思路是,利用 channel 的缓存来设定最大的并发数,配合上 sync.WaitGroup 来等待全部请求的完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package main

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

// 等待组
var wg = sync.WaitGroup{}

// 互斥锁
var mux sync.Mutex

// 同时并发数
var channelNum = 100

// 发送请求总数
var sendNum = 10000

// 成功数
var successNum = 0

// 失败数
var failNum = 0

// 请求的网址
var url = "https://tools.hongfs.cn/v2/ip"

func main() {
// 创建带缓存的通道,缓存数是并发数
ch := make(chan bool, channelNum)

for i := 0; i < sendNum; i++ {
wg.Add(1)

go get(ch, int64(i))
}

// 阻塞
wg.Wait()
}

func get(ch chan bool, i int64) {
// 返回时,等待组计数自减
defer wg.Done()

// 发送到通道,如果满了那这里会阻塞
ch <- true

client := http.Client{
Timeout: 1 * time.Second, // 请求超时
}

resp, err := client.Get(url)

// 请求没有 err 时需要关闭连接
if err == nil {
defer resp.Body.Close()
}

// 锁一下,避免成功失败数的统计有问题
mux.Lock()

defer mux.Unlock()

if err != nil {
// 请求失败
failNum++
} else if resp.StatusCode != 200 {
// 请求状态码异常
failNum++
} else {
// 成功请求
successNum++
}

fmt.Printf("I: %d, 成功数: %d,失败数:%d\n", i+1, successNum, failNum)

// 释放当前的通道
<-ch
}
1
2
3
4
5
6
7
8
9
10
11
12
$ go run main.go
I: 9990, 成功数: 4085,失败数:5905
I: 9992, 成功数: 4085,失败数:5906
I: 9993, 成功数: 4085,失败数:5907
I: 9991, 成功数: 4085,失败数:5908
I: 9995, 成功数: 4085,失败数:5909
I: 9996, 成功数: 4085,失败数:5910
I: 9997, 成功数: 4085,失败数:5911
I: 9994, 成功数: 4085,失败数:5912
I: 9998, 成功数: 4085,失败数:5913
I: 9999, 成功数: 4085,失败数:5914
I: 10000, 成功数: 4085,失败数:5915
往上