我使用以下简单的轮询机制:
func poll() {
for {
if a {
device1()
time.Sleep(time.Second * 10)
} else {
sensor1()
time.Sleep(time.Second * 10)
}
}
}
我只需要在“a”为真时轮询device1,否则轮询sensor1。现在,通过单击UI上的按钮将“a”设置为true,这将是一个随机动作。
但由于时间的原因,在检查条件时会引入延迟。
有没有办法立即停止时间。当我得到“a”的值时,是否会睡觉? 在golang中轮询时实现此类中断的可能方法是什么?
答案 0 :(得分:4)
您无法中断time.Sleep()
。
相反,如果您在等待某事时需要听其他“事件”,则应使用频道和select
语句。 select
类似于switch
,但案例都涉及通信操作。
select
的好处是你可以列出多个案例,所有案例都引用了comm。操作(例如,频道接收或发送),以及可以进行的操作(choosing one randomly if multiple can proceed)。如果没有一个可以继续,它将阻塞(等待)直到其中一个comm。操作可以继续(除非有default
)。
使用time.After()
或使用time.Ticker
的一系列“连续”超时事件(刻度或心跳)可以实现“超时”事件。
您应该更改按钮处理程序以在频道上发送值(按钮状态),因此可以将此频道的接收添加到select
内的poll()
,并立即处理(无需等待超时或下一个滴答事件。)
见这个例子:
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
此解决方案可以轻松添加任意数量的事件源而无需更改任何内容。例如,如果您想在上述解决方案中添加“关闭”事件和“立即读取”事件,那么它就是这样的:
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)
关闭频道的优势在于你可以有任意数量的goroutine“监听”它,所有都会收到关机(这就像广播一样)。从封闭通道接收可以立即进行,产生通道元素类型的零值。
要发出“立即阅读”操作,您需要在readNowCh
上发送一个值。