golang进行超时控制

本文介绍golang进行超时控制的几种方法

基于time.After的超时控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
"time"
)

func main() {
// 空结构体不占用空间,可以用来当占位符
c := make(chan struct{})
go func() {
fmt.Println("doing something")
time.Sleep(time.Second * 5)
defer close(c)
}()
select {
case <-c:
fmt.Println("运行结束")
case <-time.After(time.Second * 3):
fmt.Println("运行超时")
}
}

将需要控制时间的服务放到go协程里

基于Context的超时控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

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

func main() {
c := make(chan struct{})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
go func() {
fmt.Println("doing something")
time.Sleep(time.Second * 5)
defer close(c)
}()
select {
case <-c:
fmt.Println("运行结束")
case <-ctx.Done():
fmt.Println("运行超时")
}
}

可以看出这边用法和time.after效果一样

对包含连续任务的总任务进行超时控制

一种是使用context.WithTimeout,该函数超时自动取消,即对ctx.Done进行赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

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

func Runtask(ctx context.Context){
for {
select {
case <-ctx.Done():
fmt.Println("timeout")
return
default:
fmt.Println("working...")
time.Sleep(time.Second)
}
}
}

func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
Runtask(ctx)
}

另一种使用ctx.WithCancel,是不带timeout的WithTimeout函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

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

func Runtask(ctx context.Context){
for {
select {
case <-ctx.Done():
fmt.Println("timeout")
return
default:
fmt.Println("working...")
time.Sleep(time.Second)
}
}
}

func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(3 * time.Second)
cancel()
}()
Runtask(ctx)
}

使用cancel,可以很方便地在别的函数体或者线程控制任务的运行