Go Channel - 我的代码看起来覆盖了频道但有效。
Go Channel - My code looks overwriting channels but works.
最近才开始学习Go,学习Goroutine的时候也是一头雾水。
这是我的代码。这打算同时完成 3 个进程。
package main
import (
"fmt"
"log"
"time"
)
func wait1(c chan string) {
time.Sleep(1 * time.Second)
log.Print("waited 1 sec")
c <- "wait1 finished\n"
}
func wait2(c chan string) {
time.Sleep(2 * time.Second)
log.Print("waited 2 sec")
c <- "wait2 finished\n"
}
func wait3(c chan string) {
time.Sleep(3 * time.Second)
log.Print("waited 3 sec")
c <- "wait3 finished\n"
}
func main() {
c := make(chan string, 3)
log.Print("started")
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := <-c, <-c, <-c
log.Print("finished")
fmt.Println(w1, w2, w3)
}
对我来说,这部分看起来是将不同的函数输入同一个名为 c 的通道,并尝试打印从 c 接收到的值。
c := make(chan string, 3)
log.Print("started")
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := <-c, <-c, <-c
log.Print("finished")
fmt.Println(w1, w2, w3)
但是,如您所见,输出是我所期望的。它同时处理3个函数和returns "finished"语句。
2015/11/25 09:41:31 started
2015/11/25 09:41:32 waited 1 sec
2015/11/25 09:41:33 waited 2 sec
2015/11/25 09:41:34 waited 3 sec
2015/11/25 09:41:34 finished
wait1 finished
wait2 finished
wait3 finished
为什么没有必要创建 3 个不同的通道,如 c1、c2、c3...?
为什么即使我使用的是同一个名为 c 的通道,值也没有被覆盖?
据我了解,您将渠道视为一个变量。一个可以保存一些值的变量。所以如果有一些 value1
而你写了另一个 value2
你基本上希望 value1
消失。哪里错了。
尝试把channels看成是buffer或者priority queue(有些人觉得比较粗糙)。 Channel 有它的大小(你的第三个变量 3
),它告诉你可以同时有多少个值。一旦你将一些东西放入通道,你可以将它视为优先级等于完成此 go-routine 所需时间的进程。
因此,在您的情况下,您使用 go wait()
将 3 个元素放入优先级队列中,然后使用 w1, w2, w3 := <-c, <-c, <-c
从队列中提取元素。所以什么都不会被覆盖。
无缓冲通道在发送数据之前同步。因此,在这种情况下,您在分配行中对 <-c
的连续调用会阻塞,直到另一端的等待函数发送通过。
Markus 提出了一个很好的观点,应该指出的是 w1, w2, w3 := <-c, <-c, <-c
之所以有效,是因为您错开了不同等待函数的等待时间。如果这些函数在通道上发送数据之前等待了任意时间,您将无法保证 w2 被分配给从 wait2 发送的结果。它只会被设置为通过通道发送的第二个值。
最近才开始学习Go,学习Goroutine的时候也是一头雾水。 这是我的代码。这打算同时完成 3 个进程。
package main
import (
"fmt"
"log"
"time"
)
func wait1(c chan string) {
time.Sleep(1 * time.Second)
log.Print("waited 1 sec")
c <- "wait1 finished\n"
}
func wait2(c chan string) {
time.Sleep(2 * time.Second)
log.Print("waited 2 sec")
c <- "wait2 finished\n"
}
func wait3(c chan string) {
time.Sleep(3 * time.Second)
log.Print("waited 3 sec")
c <- "wait3 finished\n"
}
func main() {
c := make(chan string, 3)
log.Print("started")
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := <-c, <-c, <-c
log.Print("finished")
fmt.Println(w1, w2, w3)
}
对我来说,这部分看起来是将不同的函数输入同一个名为 c 的通道,并尝试打印从 c 接收到的值。
c := make(chan string, 3)
log.Print("started")
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := <-c, <-c, <-c
log.Print("finished")
fmt.Println(w1, w2, w3)
但是,如您所见,输出是我所期望的。它同时处理3个函数和returns "finished"语句。
2015/11/25 09:41:31 started
2015/11/25 09:41:32 waited 1 sec
2015/11/25 09:41:33 waited 2 sec
2015/11/25 09:41:34 waited 3 sec
2015/11/25 09:41:34 finished
wait1 finished
wait2 finished
wait3 finished
为什么没有必要创建 3 个不同的通道,如 c1、c2、c3...? 为什么即使我使用的是同一个名为 c 的通道,值也没有被覆盖?
据我了解,您将渠道视为一个变量。一个可以保存一些值的变量。所以如果有一些 value1
而你写了另一个 value2
你基本上希望 value1
消失。哪里错了。
尝试把channels看成是buffer或者priority queue(有些人觉得比较粗糙)。 Channel 有它的大小(你的第三个变量 3
),它告诉你可以同时有多少个值。一旦你将一些东西放入通道,你可以将它视为优先级等于完成此 go-routine 所需时间的进程。
因此,在您的情况下,您使用 go wait()
将 3 个元素放入优先级队列中,然后使用 w1, w2, w3 := <-c, <-c, <-c
从队列中提取元素。所以什么都不会被覆盖。
无缓冲通道在发送数据之前同步。因此,在这种情况下,您在分配行中对 <-c
的连续调用会阻塞,直到另一端的等待函数发送通过。
Markus 提出了一个很好的观点,应该指出的是 w1, w2, w3 := <-c, <-c, <-c
之所以有效,是因为您错开了不同等待函数的等待时间。如果这些函数在通道上发送数据之前等待了任意时间,您将无法保证 w2 被分配给从 wait2 发送的结果。它只会被设置为通过通道发送的第二个值。