Golang:select 语句在不应该退出的时候退出
Golang: select statement exits when it shouldn't
我正在尝试创建一个程序,分别每 3 秒、8 秒和 24 秒打印一次 "Eat"
、"Work"
、"Sleep"
。这是我的代码:
package main
import (
"fmt"
"time"
)
func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings
ch := make(chan string) // buffered/unbuffered?
go func() {
for {
msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text
ch <- msg
time.Sleep(delay) // waits according to specification
}
}()
return ch
}
func main() {
ch1 := Remind("Eat", 1000*1000*1000*3) // every third second
ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second
ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
它的问题是它在打印时间后立即停止 运行,然后是 "Eat"
。在我读过的其他示例中,select
语句会永远持续下去。为什么现在没有了?
我不知道你在哪里读到 select
会永远持续下去,但它不会。
一旦case
被执行,select
语句就是"done"。如果case
s中指定的none个通信操作可以进行和没有default
分支,select
会阻塞,因为只要任何一个com。操作可以继续。但是一旦执行了case
,select
就不会重复了。
阅读规范中的相关部分:Select statements。
把它放在一个无穷无尽的for
中让它永远重复:
for {
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
旁注:
您可以创建 time.Duration
values much easier, using constants from the time
包:
ch1 := Remind("Eat", 3*time.Second) // every third second
ch2 := Remind("Work", 8*time.Second) // every eighth second
ch3 := Remind("Sleep", 24*time.Second) // every 24th second
您可能还想查看 time.Ticker
类型,它用于与您的 Remind()
函数类似的任务。
Go 中的 select
大多类似于 switch 控制语句,有时也称为通信开关。 select
侦听通道上的传入数据,但也可能存在在通道上发送值的情况。一言以蔽之,select
用于在并发执行的 goroutine 上获取或发送值。
在你的例子中因为你在主goroutine中执行当前时间,它总是被执行。但是因为其他 goroutines 是在 select 语句中执行的,所以它们并不总是有机会被执行,因为一旦 case
被执行,通道就会阻塞。
select 的作用:
- 如果所有都被阻止,它会等到一个可以继续
- 如果可以进行多个,则随机选择一个。
- 当 none 个通道操作可以继续并且存在默认子句时,将执行此操作:默认总是 运行nable(即:准备执行)。
在带有默认大小写的 select 语句中使用发送操作保证发送将是非阻塞的!
要运行永远在for循环中使用它:
package main
import (
"fmt"
"time"
)
func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings
ch := make(chan string) // buffered/unbuffered?
go func() {
for {
msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text
ch <- msg
time.Sleep(delay) // waits according to specification
}
}()
return ch
}
func main() {
ch1 := Remind("Eat", 1000*1000*1000*3) // every third second
ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second
ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second
for {
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
}
我正在尝试创建一个程序,分别每 3 秒、8 秒和 24 秒打印一次 "Eat"
、"Work"
、"Sleep"
。这是我的代码:
package main
import (
"fmt"
"time"
)
func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings
ch := make(chan string) // buffered/unbuffered?
go func() {
for {
msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text
ch <- msg
time.Sleep(delay) // waits according to specification
}
}()
return ch
}
func main() {
ch1 := Remind("Eat", 1000*1000*1000*3) // every third second
ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second
ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
它的问题是它在打印时间后立即停止 运行,然后是 "Eat"
。在我读过的其他示例中,select
语句会永远持续下去。为什么现在没有了?
我不知道你在哪里读到 select
会永远持续下去,但它不会。
一旦case
被执行,select
语句就是"done"。如果case
s中指定的none个通信操作可以进行和没有default
分支,select
会阻塞,因为只要任何一个com。操作可以继续。但是一旦执行了case
,select
就不会重复了。
阅读规范中的相关部分:Select statements。
把它放在一个无穷无尽的for
中让它永远重复:
for {
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
旁注:
您可以创建 time.Duration
values much easier, using constants from the time
包:
ch1 := Remind("Eat", 3*time.Second) // every third second
ch2 := Remind("Work", 8*time.Second) // every eighth second
ch3 := Remind("Sleep", 24*time.Second) // every 24th second
您可能还想查看 time.Ticker
类型,它用于与您的 Remind()
函数类似的任务。
select
大多类似于 switch 控制语句,有时也称为通信开关。 select
侦听通道上的传入数据,但也可能存在在通道上发送值的情况。一言以蔽之,select
用于在并发执行的 goroutine 上获取或发送值。
在你的例子中因为你在主goroutine中执行当前时间,它总是被执行。但是因为其他 goroutines 是在 select 语句中执行的,所以它们并不总是有机会被执行,因为一旦 case
被执行,通道就会阻塞。
select 的作用:
- 如果所有都被阻止,它会等到一个可以继续
- 如果可以进行多个,则随机选择一个。
- 当 none 个通道操作可以继续并且存在默认子句时,将执行此操作:默认总是 运行nable(即:准备执行)。
在带有默认大小写的 select 语句中使用发送操作保证发送将是非阻塞的!
要运行永远在for循环中使用它:
package main
import (
"fmt"
"time"
)
func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings
ch := make(chan string) // buffered/unbuffered?
go func() {
for {
msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text
ch <- msg
time.Sleep(delay) // waits according to specification
}
}()
return ch
}
func main() {
ch1 := Remind("Eat", 1000*1000*1000*3) // every third second
ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second
ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second
for {
select { // chooses one channel that is not empty. Should run forever (?)
case rem1 := <-ch1:
fmt.Println(rem1)
case rem2 := <-ch2:
fmt.Println(rem2)
case rem3 := <-ch3:
fmt.Println(rem3)
}
}
}