这周在开发项目过程中遇到了一点问题,代码示例如下:
package main
import (
"fmt"
"strconv"
"time"
)
var (
verchan chan string
maxLength = 3
)
func main() {
verchan = make(chan string, 50)
for i := 0; i < 4; i++ {
verchan <- strconv.Itoa(i)
}
go listener()
time.Sleep(500000000000)
}
func listener() {
var buffer []string
startTime := time.Now().Unix()
for {
for chanVal := range verchan {
buffer = append(buffer, chanVal)
if len(buffer) == maxLength { // buffer length 达到 maxLength 执行一次批量操作
go func(buffer []string) {
// do something
fmt.Println(buffer, "go buffer")
startTime = time.Now().Unix()
}(buffer)
buffer = make([]string, 0) //
fmt.Println(buffer, "buffer")
}
}
endTime := time.Now().Unix()
timeSpace := endTime - startTime
fmt.Println(timeSpace, "timeSpace")
if timeSpace > 2 {
// do something
startTime = time.Now().Unix()
}
time.Sleep(time.Millisecond * 500)
}
}
这段代码的本意是想做一个批量的数据入库操作,每500毫秒从channel中取出数据 当 buffer 的长度达到设置的 maxLength 时,执行一次批量操作,或者超过 2s 没有数据写入channel 中直接将 buffer 的数据进行一次批量操作。
但程序运行后发现并未达到我们的预期 结果如下:
[] buffer
[] go buffer
究其原因很简单,忽略了for range channel的一个特性,不同于for i :=0; i<len; i++ 这种循环(这种固定了在channel中取len条数据),for range channel 会一直遍历等待通道 close 知道原因修改就简单了:
for {
verlen := len(verchan)
for i := 0; i < verlen; i++ {
buffer = append(buffer, <-verchan)
if len(buffer) == maxLength {
go func(buffer []string) {
}(buffer)
buffer = []string{}
fmt.Println(buffer, "bufferDEL")
}
}
...
}
这样的方式就能到达想要的效果了