什么是context
go从1.7版本之后开始引入了context,它的作用主要是传递上下文信息,像一个大容器,里面也可以存储k-v等数据。之后很多标准库基本上都把函数的第一个参数默认为context参数
作为天然适合写并发的语言,在处理一个请求适合往往都会开启多个goroutine,那么这些goroutine之前通常需要共享一些共享信息,这个时候context就派上用场了
context可以运用到哪些场景
type Context interface {
//返回一个time.Time,表示当前Context应该结束的时间,ok则表示有结束时间
Deadline() (deadline time.Time, ok bool)
//当Context被取消或者超时时候返回的一个close的channel,告诉给context相关的函数要停止当前工作然后返回了。(这个有点像全局广播)
Done() <-chan struct{}
//context被取消的原因
Err() error
//context实现共享数据存储的地方,是协程安全的
Value(key interface{}) interface{}
}
- web编程中,一个请求对应多个goroutine之间的数据交互
- 超时控制
- 上下文控制
context实战应用
WithCancel实战
- 多个任务同时工作,通过cancel释放取消信号,所有任务停止
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
var urls chan string
var preStr = "http"
func main() {
//定义一个根context
parent := context.Background()
urls = make(chan string)
//创建一个WithCancel
ctx, cancel := context.WithCancel(parent)
//任务一下载图片
downloadPicture(ctx)
//任务二获取图片地址
getUrls(ctx)
time.Sleep(time.Second * 5)
cancel()
time.Sleep(time.Second * 10)
}
func downloadPicture(ctx context.Context) {
go func() {
for {
select {
//收到停止信号后,return
case <-ctx.Done():
fmt.Println("downloadPicture stop")
return
case url := <-urls:
fmt.Println("download page url=" + url)
}
}
}()
}
func getUrls(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("getUrls stop")
return
default:
num := rand.Int31()
url := fmt.Sprintf("url=%d", num)
urls <- url
time.Sleep(time.Second)
}
}
}()
}
WithDeadline&WithTimeout实战
- 源码中,其实WithTimeout内部就是调用的WithDeadline,两者的效果是一样的
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
var urls1 chan string
func main() {
//定义一个根context
parent := context.Background()
urls1 = make(chan string)
//ctx, cancel := context.WithDeadline(parent,time.Now().Add(5))
ctx, cancel := context.WithTimeout(parent,time.Second * 5)
DownloadPicture1(ctx)
GetUrls1(ctx)
time.Sleep(time.Second * 10)
defer cancel()
}
func DownloadPicture1(ctx context.Context) {
go func() {
for {
select {
//收到停止信号后,return
case <-ctx.Done():
fmt.Println("downloadPicture stop")
return
case url := <-urls1:
fmt.Println("download page url=" + url)
}
}
}()
}
func GetUrls1(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("getUrls stop")
return
default:
num := rand.Int31()
url := fmt.Sprintf("url=%d", num)
urls1 <- url
time.Sleep(time.Second)
}
}
}()
}
WithValue
package main
import (
"context"
"fmt"
)
func main() {
//定义一个根context
parent := context.Background()
//添加k-v值
ctx := context.WithValue(parent,"test","testval")
//获取val值
val := ctx.Value("test").(string)
fmt.Println(val)
}
网友评论