更改goroutine睡眠时间

时间:2018-06-20 23:54:00

标签: go process sleep goroutine

Go中,我可以编写这样的代码来创建休眠时间5秒的gorouting。

func sleep(link chan interface{}){
    time.Sleep(5 * time.Second)
    fmt.Println("I've slept for 5 sec")
    link <- struct {}{}
}

func main() {
    var link = make(chan interface{})
    go sleep(link)
    time.Sleep(1 * time.Second)
    // here I want to change the remaining sleeping time of `sleep` goroutine to 0.5 sec
    <- link
}

如果在main函数中我改变了主意,并决定睡眠者不应该5秒而是应该3睡眠。如果goroutine已经开始进入睡眠状态(例如1秒进入睡眠状态)怎么办?

更新

我的意思是那里有东西,我可以在睡眠时管理该独特的goroutine。像给它发出有关减少或增加睡眠时间的命令一样:

func main() {
    // ...
    time.Sleep(1)
    something.ManageRemainingTime(10)
    time.Sleep(5)
    something.ManageRemainingTime(100)
    time.Sleep(8)
    something.ManageRemainingTime(0.5)
    // ...
}

3 个答案:

答案 0 :(得分:3)

一种方法是使用context对象。具体来说,是使用WithTimeout创建的一个。

上下文对象提供了一种向工作人员发送“取消”信号的方法。在这种情况下,您的工作人员实际上并没有做任何事情,但是仍然适合该范例。

示例为:

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

func sleep(ctx context.Context, wg *sync.WaitGroup) {
    sctx, _ := context.WithTimeout(ctx, 5*time.Second)
    tStart := time.Now()
    <-sctx.Done() // will sit here until the timeout or cancelled
    tStop := time.Now()
    fmt.Printf("Slept for %s\n", tStop.Sub(tStart))
    wg.Done()
}

func main() {
    ctx, cancelFunc := context.WithCancel(context.Background())
    wg := sync.WaitGroup{}
    wg.Add(1)
    go sleep(ctx, &wg)

    if true {
        time.Sleep(3 * time.Second)
        cancelFunc()
    }
    wg.Wait()
}

https://play.golang.org/p/2Krx4PsxFKL

if true {更改为if false {,您会看到Slept for ...的变化。

答案 1 :(得分:3)

如果您只需要“唤醒”正在睡眠的goroutine的方法,则可以使用sync.Once确保函数仅被调用一次,然后返回一个通道,以便您可以设置更快的“触发时间”,这样的事情:

func sleep(callback func(), seconds int) chan int {
    once := sync.Once{}
    wakeup := make(chan int)
    go func() {
        for sleep := range wakeup {
            go func() {
                time.Sleep(time.Duration(sleep) * time.Second)
                once.Do(callback)
            }()
        }
    }()
    wakeup <- seconds
    return wakeup
}


func main() {
        wg := sync.WaitGroup{}
        wg.Add(1)
        t := time.Now()
        wakeup := sleep(func() {
            fmt.Println("Hello, playground")
            wg.Done()
        }, 5)
        wakeup <- 2
        wg.Wait()
        fmt.Println(time.Since(t))
}

https://play.golang.org/p/BRNtaBPKpLW

答案 2 :(得分:2)

一种方法是使用timer。您可以在计时器上调用Stop(),但这会在不唤醒正在等待的内容的情况下将其停止。因此,您然后使用Reset()将其设置为新值,特别是0,它将立即触发它。

示例:

package main

import (
    "fmt"
    "sync"
    "time"
)

func sleep(wg *sync.WaitGroup) *time.Timer {
    timer := time.NewTimer(5 * time.Second)
    go func() {
        tStart := time.Now()
        <-timer.C
        tStop := time.Now()
        fmt.Printf("Slept for %s\n", tStop.Sub(tStart))
        wg.Done()
    }()
    return timer
}

func main() {
    wg := sync.WaitGroup{}
    wg.Add(1)
    timer := sleep(&wg)
    if true {
        time.Sleep(3 * time.Second)
        if timer.Stop() {
            timer.Reset(0)
        }
    }
    wg.Wait()
}

https://play.golang.org/p/b3I65kAujR4

if true {更改为if false {,您会看到Slept for ...的变化。