dqftyn1717 2018-05-14 08:50
浏览 370
已采纳

Golang:中断有时间的无限轮询。睡眠

I am using the following simple polling mechanism:

    func poll() {

        for {
            if a {
                device1()
                time.Sleep(time.Second * 10)
            } else {
                sensor1()
                time.Sleep(time.Second * 10)
            }
        }
    }

I need to poll the device1 only if "a" is true otherwise poll the sensor1. Now here "a" will be set to true by clicking the button on UI which will be a random act.

But because of time.Sleep, delay get introduced while checking the condition.

Is there any way to immediately stop time.Sleep when I get the value for "a"? what are the possible ways to implement such interrupts while polling in golang?

  • 写回答

1条回答 默认 最新

  • duankun9280 2018-05-14 10:07
    关注

    You cannot interrupt a time.Sleep().

    Instead if you need to listen to other "events" while waiting for something, you should use channels and the select statements. A select is similar to a switch, but with the cases all referring to communication operations.

    The good thing of select is that you may list multiple cases, all refering to comm. ops (e.g. channel receives or sends), and whichever operation can proceed will be chosen (choosing one randomly if multiple can proceed). If none can proceed, it will block (wait) until one of the comm. ops can proceed (unless there's a default).

    A "timeout" event may be realized using time.After(), or a series of "continuous" timeout events (ticks or heartbeats) using time.Ticker.

    You should change your button handler to send a value (the button state) on a channel, so receiving from this channel can be added to the select inside poll(), and processed "immediately" (without waiting for a timeout or the next tick event).

    See this example:

    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") }
    

    Testing it:

    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)
    

    Output (try it on the 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
    

    This solution makes it easy to add any number of event sources without changing anything. For example if you want to add a "shutdown" event and a "read-now" event to the above solution, this is how it would look like:

    for {
        select {
        case isDevice = <-buttonCh:
        case <-ticker.C:
            read()
        case <-readNowCh:
            read()
        case <-shutdownCh:
            return
        }
    }
    

    Where shutdownCh is a channel with any element type, and to signal shutdown, you do that by closing it:

    var shutdownCh = make(chan struct{})
    
    // Somewhere in your app:
    close(shutdownCh)
    

    Closing the channel has the advantage that you may have any number of goroutines "monitoring" it, all will receive the shutdown (this is like broadcasting). Receive from a closed channel can proceed immediately, yielding the zero-value of the channel's element type.

    To issue an "immediate read" action, you would send a value on readNowCh.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同
  • ¥50 如何openEuler 22.03上安装配置drbd
  • ¥20 ING91680C BLE5.3 芯片怎么实现串口收发数据
  • ¥15 无线连接树莓派,无法执行update,如何解决?(相关搜索:软件下载)
  • ¥15 Windows11, backspace, enter, space键失灵