golang 里面 reader.Read 数据,通过 chan 发送给其他协程使用的过程中,遇到一个奇奇怪怪的问题。
问题复现:
func writeFile() {
for {
func(d []byte){
saveFilemux.Lock()
defer func() {
saveFilemux.Unlock()
}()
if !writeStatus || saveFile==nil {
return
}
if _,err:=saveFile.Write(d[:len(d)]);err!=nil {
common.Error("写入文件失败",saveFile.Name(),err)
}
}(<-mediaChan)
}
}
// 下载
func (r *Requestmove) downserver() {
req, err := http.NewRequest("GET", r.Link, nil)
if err != nil {
common.Error("初始化请求失败", err.Error())
os.Exit(0)
}
client := http.Client{}
resp, err := client.Do(req)
defer common.CloseResp(resp)
if err != nil {
common.Error("请求失败")
return
}
buff := make(Video, 1024)
for {
nr, err := resp.Body.Read(buff)
if err != nil {
if err == io.EOF {
common.Log("下载读取到EOF")
break
}
common.Error("异常", err.Error())
break
}
if nr <= 0 { // 没有读取到有数据
continue
}
mediaChan<-buff[:nr]
}
common.CloseResp(resp)
}
上面的代码片段中,saveFile 写入的数据始终有问题,缺失或者数据混乱,经过反复排查有了以下结论:
如果在 for 循环外面 make buff,每次写入 channel 的 slice 都是指向同一个数组,如果 buff 的值变了,会导致写入的 slice 映射的数组的值发生变化,这样 chan 接收到的数据是混乱的。
所以上面代码中,downserver 应该是这样:
// 下载
func (r *Requestmove) downserver() {
req, err := http.NewRequest("GET", r.Link, nil)
if err != nil {
common.Error("初始化请求失败", err.Error())
os.Exit(0)
}
client := http.Client{}
resp, err := client.Do(req)
defer common.CloseResp(resp)
if err != nil {
common.Error("请求失败")
return
}
for {
buff := make(Video, 1024) // 注意看,buff改成这里定义
nr, err := resp.Body.Read(buff)
if err != nil {
if err == io.EOF {
common.Log("下载读取到EOF")
break
}
common.Error("异常", err.Error())
break
}
if nr <= 0 { // 没有读取到有数据
continue
}
mediaChan<-buff[:nr]
}
common.CloseResp(resp)
}