■实例说明
我们很容易启动一个goroutine协程执行指定任务,但如果不控制协程的执行超时时间,很容易造成程序实行超时。
1)通过context控制协程超时时间
2)协程正确返回数据的方式
3)协程错误返回数据的方式,当然有时候这不是一种错误,而是特性。详见代码注释
■实例代码
[Golang] 纯文本查看 复制代码 package main
import (
"context"
"fmt"
"time"
)
// DoJob 一个最多执行timeout时间的方法
func DoJob(timeout time.Duration) {
// 定义一个包含超时时间的context
ctx, cancel := context.WithTimeout(context.Background(), timeout)
go func() {
// 如果方法执行完成了,则理解取消ctx执行,避免无效等待
defer cancel()
// 执行业务操作,修改成自己的代码
time.Sleep(2 * time.Second)
fmt.Println("goroutine exec finished")
}()
// 等待执行完成,或超时
<-ctx.Done()
return
}
// ErrorDoJob 错误执行超时协程例子
// 这里传入了value的引用方式,即使ErrorDoJob超时返回,
// 但里面但协程本身还在执行,还会继续修改value的值。
func ErrorDoJob(timeout time.Duration, value *int) {
// 定义一个包含超时时间的context
ctx, cancel := context.WithTimeout(context.Background(), timeout)
go func() {
defer cancel()
// 执行业务操作,修改成自己的代码
time.Sleep(2 * time.Second)
*value = 10
fmt.Println("goroutine exec finished")
}()
<-ctx.Done()
return
}
// RightDoJob 正确执行超时协程的例子,虽然超时执行后协程还在执行,但结果不会返回给调用方了。
func RightDoJob(timeout time.Duration) int {
value := 0
// 定义一个包含超时时间的context
ctx, cancel := context.WithTimeout(context.Background(), timeout)
go func() {
defer cancel()
// 执行业务操作,修改成自己的代码
time.Sleep(2 * time.Second)
value = 10
fmt.Println("goroutine exec finished")
}()
<-ctx.Done()
return value
}
func main() {
// 【1】执行一个方法,最多等待3秒钟
DoJob(3 * time.Second)
// 【2】执行一个方法,并获取方法的返回值,最多等待3秒钟,
rightValue := RightDoJob(1 * time.Second)
fmt.Printf("rightValue is %d\n", rightValue)
// rightValue is 0
// 再等待一会,看rightValue值是否会发生变化
time.Sleep(3 * time.Second)
fmt.Printf("after rightValue is %d\n", rightValue)
// after rightValue is 0
// 【3】执行一个方法,并获取方法的返回值,最多等待3秒钟,
errorValue := 0
ErrorDoJob(1*time.Second, &errorValue)
fmt.Printf("errorValue is %d\n", errorValue)
// errorValue is 0
// 再等待一会,看errorValue值是否会发生变化
time.Sleep(3 * time.Second)
fmt.Printf("after errorValue is %d\n", errorValue)
// after errorValue is 10
}
|