Golang:中断 time.Sleep 的无限轮询
Golang: Interrupting infinite polling having time.Sleep
我正在使用以下简单的轮询机制:
func poll() {
for {
if a {
device1()
time.Sleep(time.Second * 10)
} else {
sensor1()
time.Sleep(time.Second * 10)
}
}
}
仅当 "a" 为真时我才需要轮询设备 1,否则轮询传感器 1。现在这里 "a" 将通过单击 UI 上的按钮设置为真,这将是一个随机行为。
但是由于 time.Sleep,在检查条件时引入了延迟。
有没有办法在我得到"a"的值时立即停止time.Sleep?
在 golang 中轮询时有哪些可能的方式来实现此类中断?
你不能打断time.Sleep()
。
相反,如果您需要在等待时收听其他 "events",您应该使用频道和 select
语句。 select
类似于switch
,但都是指通信操作。
select
的好处是你可以列出多个案例,都是指comm。操作(例如通道接收或发送),并且将选择可以进行的操作()。如果 none 可以继续,它将阻塞(等待)直到通信之一。操作可以继续(除非有 default
)。
一个"timeout"事件可以使用time.After()
, or a series of "continuous" timeout events (ticks or heartbeats) using time.Ticker
实现。
您应该更改按钮处理程序以在通道上发送一个值(按钮状态),因此可以将来自该通道的接收添加到 poll()
内的 select
,并处理 "immediately"(无需等待超时或下一个滴答事件)。
看这个例子:
func poll(buttonCh <-chan bool) {
isDevice := false
read := func() {
if isDevice {
device1()
} else {
sensor1()
}
}
ticker := time.NewTicker(1 * time.Second)
defer func() { ticker.Stop() }()
for {
select {
case isDevice = <-buttonCh:
case <-ticker.C:
read()
}
}
}
func device1() { log.Println("reading device1") }
func sensor1() { log.Println("reading sensor1") }
正在测试:
buttonCh := make(chan bool)
// simulate a click after 2.5 seconds:
go func() {
time.Sleep(2500 * time.Millisecond)
buttonCh <- true
}()
go poll(buttonCh)
time.Sleep(5500 * time.Millisecond)
输出(在 Go Playground 上尝试):
2009/11/10 23:00:01 reading sensor1
2009/11/10 23:00:02 reading sensor1
2009/11/10 23:00:03 reading device1
2009/11/10 23:00:04 reading device1
2009/11/10 23:00:05 reading device1
此解决方案可以轻松添加任意数量的事件源,而无需更改任何内容。例如,如果你想在上面的解决方案中添加一个 "shutdown" 事件和一个 "read-now" 事件,它看起来像这样:
for {
select {
case isDevice = <-buttonCh:
case <-ticker.C:
read()
case <-readNowCh:
read()
case <-shutdownCh:
return
}
}
其中 shutdownCh
是具有任何元素类型的通道,要发出关闭信号,您可以通过关闭它来实现:
var shutdownCh = make(chan struct{})
// Somewhere in your app:
close(shutdownCh)
关闭通道的好处是你可以有任意数量的 goroutines "monitoring" 它,所有的 goroutines 都会收到关闭消息(这就像广播)。从关闭的通道接收可以立即进行,产生通道元素类型的零值。
要发出 "immediate read" 操作,您将在 readNowCh
上发送一个值。
我正在使用以下简单的轮询机制:
func poll() {
for {
if a {
device1()
time.Sleep(time.Second * 10)
} else {
sensor1()
time.Sleep(time.Second * 10)
}
}
}
仅当 "a" 为真时我才需要轮询设备 1,否则轮询传感器 1。现在这里 "a" 将通过单击 UI 上的按钮设置为真,这将是一个随机行为。
但是由于 time.Sleep,在检查条件时引入了延迟。
有没有办法在我得到"a"的值时立即停止time.Sleep? 在 golang 中轮询时有哪些可能的方式来实现此类中断?
你不能打断time.Sleep()
。
相反,如果您需要在等待时收听其他 "events",您应该使用频道和 select
语句。 select
类似于switch
,但都是指通信操作。
select
的好处是你可以列出多个案例,都是指comm。操作(例如通道接收或发送),并且将选择可以进行的操作(default
)。
一个"timeout"事件可以使用time.After()
, or a series of "continuous" timeout events (ticks or heartbeats) using time.Ticker
实现。
您应该更改按钮处理程序以在通道上发送一个值(按钮状态),因此可以将来自该通道的接收添加到 poll()
内的 select
,并处理 "immediately"(无需等待超时或下一个滴答事件)。
看这个例子:
func poll(buttonCh <-chan bool) {
isDevice := false
read := func() {
if isDevice {
device1()
} else {
sensor1()
}
}
ticker := time.NewTicker(1 * time.Second)
defer func() { ticker.Stop() }()
for {
select {
case isDevice = <-buttonCh:
case <-ticker.C:
read()
}
}
}
func device1() { log.Println("reading device1") }
func sensor1() { log.Println("reading sensor1") }
正在测试:
buttonCh := make(chan bool)
// simulate a click after 2.5 seconds:
go func() {
time.Sleep(2500 * time.Millisecond)
buttonCh <- true
}()
go poll(buttonCh)
time.Sleep(5500 * time.Millisecond)
输出(在 Go Playground 上尝试):
2009/11/10 23:00:01 reading sensor1
2009/11/10 23:00:02 reading sensor1
2009/11/10 23:00:03 reading device1
2009/11/10 23:00:04 reading device1
2009/11/10 23:00:05 reading device1
此解决方案可以轻松添加任意数量的事件源,而无需更改任何内容。例如,如果你想在上面的解决方案中添加一个 "shutdown" 事件和一个 "read-now" 事件,它看起来像这样:
for {
select {
case isDevice = <-buttonCh:
case <-ticker.C:
read()
case <-readNowCh:
read()
case <-shutdownCh:
return
}
}
其中 shutdownCh
是具有任何元素类型的通道,要发出关闭信号,您可以通过关闭它来实现:
var shutdownCh = make(chan struct{})
// Somewhere in your app:
close(shutdownCh)
关闭通道的好处是你可以有任意数量的 goroutines "monitoring" 它,所有的 goroutines 都会收到关闭消息(这就像广播)。从关闭的通道接收可以立即进行,产生通道元素类型的零值。
要发出 "immediate read" 操作,您将在 readNowCh
上发送一个值。