UnBuffered Channel 不以同步方式工作
UnBuffered Channel not working in synchronous way
我对 GoLang 世界还很陌生,正在尝试 goroutines/channels。
据我了解,通道是 goroutine 之间的双向通信方式。
如果我们创建一个长度为 0 的通道,它应该是一个同步通道,这意味着除非某个 goroutine(即消费者)从通道读取值,否则生产者将无法继续前进。
我尝试了下面的例子来测试这个,但我没有得到预期的结果。
package main
import (
"fmt"
"time"
)
var done = make(chan bool)
var msgs = make(chan int)
func produce() {
for i := 0; i < 40; i++ {
//fmt.Println("sending")
fmt.Println("Produced: ", i)
msgs <- i
//fmt.Println("Channel size is: ", len(msgs))
}
fmt.Println("Before closing channel")
close(msgs)
fmt.Println("Before passing true to done")
}
func consume() {
for msg := range msgs {
//fmt.Println("Going to take one, Channel size is: ", len(msgs))
fmt.Println("Consumer: ", msg)
time.Sleep(100 * time.Millisecond)
}
done <- true
}
func main() {
go produce()
go consume()
<-done
fmt.Println("After calling DONE")
}
输出:
Produced: 0
Produced: 1
Consumer: 0
Consumer: 1
Produced: 2
Consumer: 2
...
我期望输出是
Produced: 0
Consumer: 0
Produced: 1
Consumer: 1
Produced: 2
Consumer: 2
请帮我指出我做错了什么?
(无缓冲)通道 reads/writes 将按您期望的顺序出现:一次写入;一读;一写;一读等等
然而,producer/consumer goroutines 中的 fmt.Println
调用是 非 同步的——因此生产者可能会得到它的 fmt.Println
在 consumer
.
之前进入调度程序
并且由于 consumer
睡眠 - 它自愿向调度程序发出提示,让其他 goroutines 运行 领先于它。所以 producer
很可能总是在 consumer
醒来之前得到它的第二个 fmt.Println
运行。
如果将 sleep 移动到 producer
goroutine,您可以在操场上看到预期的行为:https://play.golang.org/p/5x9_yyUaMiJ - 但是您不应该依赖这些计时技巧。如果你想确保一个函数相对于另一个 goroutine 的执行顺序,那些任务也必须同步。使用通道 reads/writes - 只有 reads/writes 保证 goroutine 安全且按顺序。
我对 GoLang 世界还很陌生,正在尝试 goroutines/channels。 据我了解,通道是 goroutine 之间的双向通信方式。 如果我们创建一个长度为 0 的通道,它应该是一个同步通道,这意味着除非某个 goroutine(即消费者)从通道读取值,否则生产者将无法继续前进。
我尝试了下面的例子来测试这个,但我没有得到预期的结果。
package main
import (
"fmt"
"time"
)
var done = make(chan bool)
var msgs = make(chan int)
func produce() {
for i := 0; i < 40; i++ {
//fmt.Println("sending")
fmt.Println("Produced: ", i)
msgs <- i
//fmt.Println("Channel size is: ", len(msgs))
}
fmt.Println("Before closing channel")
close(msgs)
fmt.Println("Before passing true to done")
}
func consume() {
for msg := range msgs {
//fmt.Println("Going to take one, Channel size is: ", len(msgs))
fmt.Println("Consumer: ", msg)
time.Sleep(100 * time.Millisecond)
}
done <- true
}
func main() {
go produce()
go consume()
<-done
fmt.Println("After calling DONE")
}
输出:
Produced: 0
Produced: 1
Consumer: 0
Consumer: 1
Produced: 2
Consumer: 2
...
我期望输出是
Produced: 0
Consumer: 0
Produced: 1
Consumer: 1
Produced: 2
Consumer: 2
请帮我指出我做错了什么?
(无缓冲)通道 reads/writes 将按您期望的顺序出现:一次写入;一读;一写;一读等等
然而,producer/consumer goroutines 中的 fmt.Println
调用是 非 同步的——因此生产者可能会得到它的 fmt.Println
在 consumer
.
并且由于 consumer
睡眠 - 它自愿向调度程序发出提示,让其他 goroutines 运行 领先于它。所以 producer
很可能总是在 consumer
醒来之前得到它的第二个 fmt.Println
运行。
如果将 sleep 移动到 producer
goroutine,您可以在操场上看到预期的行为:https://play.golang.org/p/5x9_yyUaMiJ - 但是您不应该依赖这些计时技巧。如果你想确保一个函数相对于另一个 goroutine 的执行顺序,那些任务也必须同步。使用通道 reads/writes - 只有 reads/writes 保证 goroutine 安全且按顺序。