如何调度 运行 非阻塞函数
How to schedule running non-blocking functions
我的问题是如何在每个时间间隔 N 调度 运行ning 个独立的非阻塞函数。
我最初的方法是在 select 语句中使用 go channels 以非阻塞方式接收值,并在每个函数中使用 time.Sleep(N)
来安排调用。
在下面的代码片段中,这仅适用于第一个 运行;但是,在第一次调用之后,它会不断调用 computeY()
,而不考虑 time.Sleep()
调用。
package main
import (
"fmt"
"time"
)
var (
x string = ""
y string = ""
)
func computeY(c chan string) {
time.Sleep(10 * time.Second)
fmt.Println("I'm in Y")
y = "this is Y value"
c <- y
}
func computeX(c chan string) {
time.Sleep(1 * time.Second)
x = "this is X value"
c <- x
}
func main() {
xC := make(chan string)
yC := make(chan string)
for {
go computeX(xC)
go computeY(yC)
select {
case x := <-xC:
fmt.Println(fmt.Sprintf("X: %v, Y: %v", x, y))
case y := <-yC:
fmt.Println(fmt.Sprintf("X: %v, Y: %v", x, y))
}
}
}
您在循环的每次迭代中都调用了 computeX
和 computeY
。
因为computeX
需要1秒,所以for
循环每秒迭代一次,并且在yC
获取一个值时有一个额外的时间。
这意味着您 运行 go computeY
在 t=0s
、t=1s
、t=2s
等....
第一个终止于 t=10s
,第二个终止于 t=11s
,依此类推...
如果您想确保一次只安排一个 computeX
和 computeY
,您需要将 main 更改为以下内容:
go computeX(xC)
go computeY(yC)
for {
select {
case x = <-xC:
fmt.Printf("Finished computeX: X: %v, Y: %v\n", x, y)
go computeX(xC)
case y = <-yC:
fmt.Printf("Finished computeY: X: %v, Y: %v\n", x, y)
go computeY(yC)
}
}
关于您的代码的其他一些注意事项:
x
和 y
是全局的,分配在 computeX
和 computeY
中
- 您的频道显示阴影
x
和 y
fmt.Println(fmt.Sprintf("..."))
就是 fmt.Printf("...\n")
- 您不需要将字符串初始化为
""
,这是默认值
虽然 @Marc 的回答解释了您的代码问题并展示了如何修复它,但我会尝试为您提供一些有关调度函数的模式。
模式 1:time.Ticker
A Ticker holds a channel that delivers `ticks' of a clock at intervals.
示例:
func Schedule(interval time.Duration,f func()) {
t:=time.NewTimer(interval)
go func() {
for {
<-t.C
f()
}
}()
}
模式二:time.AfterFunc
AfterFunc waits for the duration to elapse and then calls f in its own goroutine. It returns a Timer that can be used to cancel the call using its Stop method.
示例:
func Schedule(interval time.Duration,f func()) {
var wrap func()
wrap = func() {
f()
time.AfterFunc(wrap)
}
time.AfterFunc(f)
}
模式 1 更具可读性和表现力,而模式 2 在内存方面更高效。
我的问题是如何在每个时间间隔 N 调度 运行ning 个独立的非阻塞函数。
我最初的方法是在 select 语句中使用 go channels 以非阻塞方式接收值,并在每个函数中使用 time.Sleep(N)
来安排调用。
在下面的代码片段中,这仅适用于第一个 运行;但是,在第一次调用之后,它会不断调用 computeY()
,而不考虑 time.Sleep()
调用。
package main
import (
"fmt"
"time"
)
var (
x string = ""
y string = ""
)
func computeY(c chan string) {
time.Sleep(10 * time.Second)
fmt.Println("I'm in Y")
y = "this is Y value"
c <- y
}
func computeX(c chan string) {
time.Sleep(1 * time.Second)
x = "this is X value"
c <- x
}
func main() {
xC := make(chan string)
yC := make(chan string)
for {
go computeX(xC)
go computeY(yC)
select {
case x := <-xC:
fmt.Println(fmt.Sprintf("X: %v, Y: %v", x, y))
case y := <-yC:
fmt.Println(fmt.Sprintf("X: %v, Y: %v", x, y))
}
}
}
您在循环的每次迭代中都调用了 computeX
和 computeY
。
因为computeX
需要1秒,所以for
循环每秒迭代一次,并且在yC
获取一个值时有一个额外的时间。
这意味着您 运行 go computeY
在 t=0s
、t=1s
、t=2s
等....
第一个终止于 t=10s
,第二个终止于 t=11s
,依此类推...
如果您想确保一次只安排一个 computeX
和 computeY
,您需要将 main 更改为以下内容:
go computeX(xC)
go computeY(yC)
for {
select {
case x = <-xC:
fmt.Printf("Finished computeX: X: %v, Y: %v\n", x, y)
go computeX(xC)
case y = <-yC:
fmt.Printf("Finished computeY: X: %v, Y: %v\n", x, y)
go computeY(yC)
}
}
关于您的代码的其他一些注意事项:
x
和y
是全局的,分配在computeX
和computeY
中
- 您的频道显示阴影
x
和y
fmt.Println(fmt.Sprintf("..."))
就是fmt.Printf("...\n")
- 您不需要将字符串初始化为
""
,这是默认值
虽然 @Marc 的回答解释了您的代码问题并展示了如何修复它,但我会尝试为您提供一些有关调度函数的模式。
模式 1:time.Ticker
A Ticker holds a channel that delivers `ticks' of a clock at intervals.
示例:
func Schedule(interval time.Duration,f func()) {
t:=time.NewTimer(interval)
go func() {
for {
<-t.C
f()
}
}()
}
模式二:time.AfterFunc
AfterFunc waits for the duration to elapse and then calls f in its own goroutine. It returns a Timer that can be used to cancel the call using its Stop method.
示例:
func Schedule(interval time.Duration,f func()) {
var wrap func()
wrap = func() {
f()
time.AfterFunc(wrap)
}
time.AfterFunc(f)
}
模式 1 更具可读性和表现力,而模式 2 在内存方面更高效。