任务的控制
任务的控制,主要涉及到以下几个方面
- 非阻塞等待
- 超时机制
- 任务中断/退出
- 优雅退出
1 非阻塞等待
// 非阻塞等待, 收到数据,返回数据,以及true , 收不到数据,返回"", false
func nonBlockWait(c chan string) (string, bool) {
select {
//如果没有收到值,会阻塞在此
case m := <-c:
return m, true
//上面的case是阻塞的,收不到值就会等待,但是加了default,就变成非阻塞了
//因为上面的case如果收不到值,就会走到default,所以加了一个default就变成了非阻塞了
default:
return "", false
}
}
用法如下:
func main() {
c1 := messageGen("service1")
c2 := messageGen("service2")
for {
fmt.Println(<-c1)
if m, ok := nonBlockWait(c2); ok {
fmt.Println(m)
} else {
fmt.Println("no message from service2")
}
}
}
2 超时机制
// 超时机制
func timeoutWait(c <-chan string, timeout time.Duration) (string, bool) {
select {
case val := <-c:
return val, true
case <-time.After(timeout):
return "", false
}
}
用法如下:
func main() {
c2 := messageGen("service2")
for {
if m, ok := timeoutWait(c2, 2*time.Second); ok {
fmt.Println(m)
} else {
fmt.Println("no message from service2")
}
}
}
退出机制
func msgGen(name string, done chan struct{}) chan string {
c := make(chan string)
go func() {
i := 0
for {
select {
case <-time.After(time.Duration(rand.Intn(5000)) * time.Microsecond):
c <- fmt.Sprintf("service %s: message %d", name, i)
case <-done: //收到外面的值了,表明要退出了
fmt.Println("cleaning up")
return
}
i++
}
}()
return c
}
func main() {
done := make(chan struct{})
c := msgGen("service1", done)
for i := 0; i < 10; i++ {
if m, ok := timeoutWait(c, 2*time.Second); ok {
fmt.Println(m)
} else {
fmt.Println("no message from service2")
}
}
done <- struct{}{} //主动退出
time.Sleep(6 * time.Second)
}
优雅退出
func msgGen(name string, done chan struct{}) chan string {
c := make(chan string)
go func() {
i := 0
for {
select {
case <-time.After(time.Duration(rand.Intn(5000)) * time.Microsecond):
c <- fmt.Sprintf("service %s: message %d", name, i)
case <-done: //收到外面的值了,表明要退出了
fmt.Println("cleaning up")
//清理工作可能要做10分钟
time.Sleep(10 * time.Minute)
// 清理完工作做完后,要退出,此时可以把done这个chan做成一个双向的
// 清理工作完成后,再向done发一个数据
done <- struct{}{} //清理工作做过多了,发一个数据,告诉外面,要退出了,
// 此时外面如果接收了,就往下走了,return了,退出了,如果外面没有接收,此行代码会阻塞,直到外面接收
return
}
i++
}
}()
return c
}
func main() {
done := make(chan struct{})
c := msgGen("service1", done)
for i := 0; i < 10; i++ {
if m, ok := timeoutWait(c, 2*time.Second); ok {
fmt.Println(m)
} else {
fmt.Println("no message from service2")
}
}
done <- struct{}{} //主动退出
<-done //接收来自子任务是否真的完成,收到数据说明完成了,main函数走完了,就退出了
}