Golang Go语言中为何从通道取数据顺序是错误的?
新手学习 go ,从通道中获取数据为什么顺序是错乱的,下面是我写的伪代码
package main
import (
“fmt”
“io”
“net/http”
“os”
“sync”
)
var wg sync.WaitGroup
func Gets(uri string, buf chan []byte) {
resp, err := http.Get(uri)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
bufs := make([]byte, 128)
for {
n, err1 := resp.Body.Read(bufs[:])
if err1 == io.EOF {
break
}
buf <- bufs[:n]
fmt.Println(string(bufs[:n]))
}
fmt.Println(“读取数据完毕”)
close(buf)
}
func SaveFile(name string, buf chan []byte) {
defer wg.Done()
f, err2 := os.Create(name)
if err2 != nil {
return
}
defer f.Close()
for {
if data, ok := <-buf; ok {
f.Write(data)
} else {
break
}
}
f.Sync()
fmt.Println("写入数据完毕")
}
func main() {
for i := 1; i < 2; i++ {
wg.Add(1)
buf := make(chan []byte)
files1 := “test1.txt”
urils := “http://www.baidu.cn”
go SaveFile(files1, buf)
go Gets(urils, buf)
}
wg.Wait()
}
fmt.Println(string(bufs[:n]))这个和 test1.txt 中内容不一致啊,这个是为什么,各位大神帮忙分析下。
Golang Go语言中为何从通道取数据顺序是错误的?
更多关于Golang Go语言中为何从通道取数据顺序是错误的?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
如果把通道改为带缓冲的,那么顺序就更乱了<br>buf := make(chan []byte,128)<br>
更多关于Golang Go语言中为何从通道取数据顺序是错误的?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
for i := 1; i < 2; i++ {
wg.Add(1)
buf := make(chan []byte)
files1 := “test1.txt”
urils := “http://www.baidu.cn”
go SaveFile(files1, buf)
go Gets(urils, buf)
}
分别创建 2 个 SaveFile/Gets 的 goroutine 了…
因为你多次<-使用的是同一个 buffer ,可能 SaveFile 里 f.Write 还没执行完,Gets 里 resp.Body.Read 就把上一次的内容覆盖了
你分别创建了两个读 两个写的线程,并行的,肯定乱了
不要把 go 当作 await 用
让我好好想想,感觉没转过来
我好像还没反应过来
那个 for 循环不是只执行一次吗? for i := 1; i < 2; i++
为何会创建 2 个呢?
抱歉,看错了,重新过了一遍代码,问题可能出在 buf <- bufs[:n] 这句上,切片是引用,你最好 copy 到一个新的 slice 上:
newBuf := make([]byte, n)
copy(newBuf, bufs[:n])
buf <- newBuf
试一下看看
好的,我去试下,非常感谢
的确是可以了,正常了,但是为何拷贝过去就正常了呢?
因为切片的切片还是指向同一个底层数组,在 write 的时候底层数组也同时被 read 操作覆盖了。
举个例子:
a := []int{1,2,3}
b := a[:1]
a[0] = 4
fmt.Println(b) // [4]
具体可以阅读这篇文章:
https://go.dev/blog/slices-intro
非常感谢,我去看下文章
在Golang(Go语言)中,从通道(channel)取数据的顺序通常是与发送数据的顺序一致的,但这依赖于几个关键因素,包括通道的类型(无缓冲或有缓冲)、并发执行的逻辑以及是否有多个goroutine在读写同一个通道。
如果你遇到从通道取数据顺序错误的情况,可能的原因包括:
-
并发执行:多个goroutine可能同时向通道发送或从中接收数据,这会导致数据到达的顺序与发送顺序不一致。Go语言的并发模型不保证goroutine的执行顺序。
-
有缓冲通道:对于有缓冲的通道,如果发送操作发生在接收操作之前,并且缓冲区未满,数据会按照发送顺序存储在缓冲区中。然而,如果接收操作在多个goroutine中并发进行,数据被取出的顺序可能会因为并发的执行而显得“乱序”。
-
通道关闭与关闭通知:如果通道在数据完全发送完毕前被关闭,且接收方没有正确处理通道关闭的情况(如使用
range
循环接收数据),可能会导致接收到的数据不完整或顺序错误。 -
编程错误:检查代码中是否存在逻辑错误,如错误的通道使用、数据竞争或同步问题,这些都可能导致数据顺序看起来不正确。
确保通道数据顺序的正确性通常需要仔细设计并发逻辑,使用适当的同步机制(如互斥锁、等待组等),并正确处理通道的关闭和数据的接收。