社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
package main
import (
"os"
"bufio"
"io"
"fmt"
)
func main() {
err := ddImage(`E:大文件.txt`, ``)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("程序执行完毕")
}
type Resource struct {
Index uint64
Buffer []byte
Size int
Err error
RefreshedBuffer []byte
}
func ddImage(ddPath, ddDstPath string) error {
reader, err := os.Open(ddPath)
if err != nil {
return err
}
defer reader.Close()
br := bufio.NewReader(reader)
//writer, err := os.OpenFile(ddDstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
//if err != nil {
// return err
//}
//defer writer.Close()
const bufferSize int64 = 1024 * 1024
chanCount := 30
writeChan := make(chan *Resource, chanCount)
go readBufioData(br, bufferSize, writeChan)
for {
data := <-writeChan
if data.Err != nil && data.Err != io.EOF {
return data.Err
}
if data.Size > 0 {
if !CompareSlice(data.Buffer, data.RefreshedBuffer) {
fmt.Printf("Buffer:%p, RefreshedBuffer:%pn", data.Buffer, data.RefreshedBuffer)
fmt.Printf("&Buffer:%p, &RefreshedBuffer:%pn", &data.Buffer, &data.RefreshedBuffer)
return fmt.Errorf("两个slice不同了")
}
//if _, err = writer.Write(data.Buffer); err != nil {
// return err
//}
}
if data.Err == io.EOF {
return nil
}
if data.Err != nil {
return data.Err
}
}
}
func readBufioData(reader *bufio.Reader, bufferSize int64, compChan chan *Resource) {
buf := make([]byte, bufferSize)
for {
refreshedBuf := buf
n, err := reader.Read(buf)
resource := new(Resource)
resource.Size = n
resource.Buffer = buf[:n]
resource.Err = err
resource.RefreshedBuffer = refreshedBuf[:n]
compChan <- resource
if err != nil {
if err != io.EOF {
fmt.Println(err)
}
break
}
}
fmt.Println("read exit")
}
func CompareSlice(a, b []byte) bool {
if len(a) != len(b) {
return false
}
if (a == nil) != (b == nil) {
return false
}
for key, value := range a {
if value != b[key] {
return false
}
}
return true
}
可能的结果
read exit
程序执行完毕
Buffer:0xc000092000, RefreshedBuffer:0xc000092000
&Buffer:0xc0001940f8, &RefreshedBuffer:0xc000194128
两个slice不同了
先来看下传的值
接下来,主要看结构体Resource
的Buffer
和RefreshedBuffer
在传输中的区别
Buffer是使用的一开始只初始化一次的buf来作为源数据,而RefreshedBuffer是相当于每次重新分配了新的地址空间的buf。
我们再添加一些日志信息打印,看下buf
,resource
,resource.Buffer
的地址信息。
func readBufioData(reader *bufio.Reader, bufferSize int64, compChan chan *Resource) {
buf := make([]byte, bufferSize)
for {
refreshedBuf := buf
n, err := reader.Read(buf)
resource := new(Resource)
resource.Size = n
resource.Buffer = buf[:n]
resource.Err = err
resource.RefreshedBuffer = refreshedBuf[:n]
fmt.Printf("buf:%p, resource:%p, resource.Buffer:%pn", buf, resource, resource.Buffer)
compChan <- resource
if err != nil {
if err != io.EOF {
fmt.Println(err)
}
break
}
}
fmt.Println("read exit")
}
可以得到如下输出
由此可见,当 resource
通过channel传输的时候,虽然每个resource都是新分配地址的值,但是 resource.Buffer
却指向的仍然是原始的buf的地址。
所以,在channel的接收端,会出现 Buffer
和 RefreshedBuffer
不相等的情况,即:由于channel是带缓存的,channel的缓存还未及时读完,之前的 Buffer
切片内容已经被修改,导致channel缓存中的 Buffer
都变成了最新的输入端的 buf
值。
对于经常接触 C/C++
的人来说,这种问题应该不太会出现。在go中使用切片传值的时候,一定要注意切片的引用传值的问题。类似这种for循环写切片的时候,若对性能没有很强烈的要求,可以每次都 make
一个新的切片。go中切片的坑还是挺多的,使用时一定要多留意一下。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!