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

15 回复

如果把通道改为带缓冲的,那么顺序就更乱了
<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在读写同一个通道。

如果你遇到从通道取数据顺序错误的情况,可能的原因包括:

  1. 并发执行:多个goroutine可能同时向通道发送或从中接收数据,这会导致数据到达的顺序与发送顺序不一致。Go语言的并发模型不保证goroutine的执行顺序。

  2. 有缓冲通道:对于有缓冲的通道,如果发送操作发生在接收操作之前,并且缓冲区未满,数据会按照发送顺序存储在缓冲区中。然而,如果接收操作在多个goroutine中并发进行,数据被取出的顺序可能会因为并发的执行而显得“乱序”。

  3. 通道关闭与关闭通知:如果通道在数据完全发送完毕前被关闭,且接收方没有正确处理通道关闭的情况(如使用range循环接收数据),可能会导致接收到的数据不完整或顺序错误。

  4. 编程错误:检查代码中是否存在逻辑错误,如错误的通道使用、数据竞争或同步问题,这些都可能导致数据顺序看起来不正确。

确保通道数据顺序的正确性通常需要仔细设计并发逻辑,使用适当的同步机制(如互斥锁、等待组等),并正确处理通道的关闭和数据的接收。

回到顶部