改变 goroutine 休眠的时间
Change the time of goroutine sleeping
在 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)
// ...
}
一种方法是使用 context
object. Specifically one created with WithTimeout
.
上下文对象提供了一种向 worker 发送 "cancel" 信号的方法。在这种情况下,您的工人并没有真正做任何事情,但仍然符合范例。
示例为:
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 ...
的变化。
如果您只需要一种 "wakeup" 休眠 goroutine 的方法,您可以使用 sync.Once
来确保您的函数只被调用一次,然后 return 一个通道,这样您就可以早点设置 "trigger time",所以这样的:
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))
}
一种方法是使用 timer
. You can call Stop()
on a timer, but this stops it without waking up whatever is waiting on it. So you then use 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 ...
的变化。
在 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)
// ...
}
一种方法是使用 context
object. Specifically one created with WithTimeout
.
上下文对象提供了一种向 worker 发送 "cancel" 信号的方法。在这种情况下,您的工人并没有真正做任何事情,但仍然符合范例。
示例为:
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 ...
的变化。
如果您只需要一种 "wakeup" 休眠 goroutine 的方法,您可以使用 sync.Once
来确保您的函数只被调用一次,然后 return 一个通道,这样您就可以早点设置 "trigger time",所以这样的:
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))
}
一种方法是使用 timer
. You can call Stop()
on a timer, but this stops it without waking up whatever is waiting on it. So you then use 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 ...
的变化。