#### 我有一些抓取操作,需要1秒钟实现10个api的请求,我把那些数据,临时存储到数组里面,但是不知道怎么通过并发的形式实现
```go
func main() {
timeout := time.NewTicker(1 * time.Second).C
var zips = []string{"01", "02", "03", "04", "05", "06", "07", "08", "14", "15", "16", "09", "10", "11", "12", "13", "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", "81", "51", "52", "53", "54", "55", "82", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "77", "78", "75", "76", "79", "80"}
for {
select {
case <-timeout:
println("时间:", time.Now().Second())
for i := 0; i < 10; i++ {
println(zips[i])
}
}
}
}
```
我理解,楼主的意思大概如下。
有100条原始条件,然后可以造出10000条请求,请求server的时候,需要控制并发,不能超过10条/秒。
我觉得,最简单的建模就是(假设goN是一个go程):
```
go1 readCondition -> chan *Contidion
go2 chan *Condition -> buildRequest -> chan *Request
go3 chan *Request -> sleepAndDoRequest()
```
代码大概如下(代码未经调试,不保证bug free,但思路基本清楚):
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"runtime"
"sync"
"time"
)
type Condition struct {
Start int
End int
BaseSetting string
}
func readContidion(conditions chan <- *Condition) {
for i:= 0; i<100; i ++ {
c := &Condition{
Start:i,
End:i+1,
}
conditions <- c
}
}
func buildRequest(conditions <- chan *Condition, reqs chan <- *http.Request ) {
for c := range conditions {
for i := c.Start; i < c.End; i++ {
rawURL := fmt.Sprintf("http://www.baidu.com?s=xx&i=%v", i)
u, _ := url.Parse(rawURL)
req := &http.Request{
URL: u,
}
reqs <- req
}
}
}
func doRequest(reqs <- chan *http.Request ,wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done()
t := time.NewTicker(time.Second / 10)
for {
select {
case <- t.C:
req := <- reqs
wg.Add(1)
go func() { // 用go保证不阻塞doRequest,控制并发
defer wg.Done()
c := &http.Client{}
resp, err := c.Do(req)
if err != nil {
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
log.Printf("resp body = %s\n", body)
} else {
log.Println(err)
}
}()
}
}
}
func main() {
log.SetFlags(log.LstdFlags)
conditions := make(chan *Condition, 5)
requests := make(chan *http.Request, 5)
wg := &sync.WaitGroup{} // 用wg保证go程不会因为主go程退出而退出
go doRequest(requests, wg) // 先启动,保证wg一定已经被.Add
runtime.Gosched()
go readContidion(conditions)
go buildRequest(conditions, requests)
wg.Wait()
}
```
后续的改进点,实际BuildCondition这块逻辑,如果可以确认速度够快,无需独立使用go程,可以和buildReq合并到一处,最终写 `*req` 作为一个分割点。
```
go1 readContidion->buildReq
go2 readReq -> go doReq()
```
#12