1. 什么是context?
Context是Go语言提供的一种用来传递请求范围内变量、取消操作以及处理超时等的机制。在并发编程中,通常情况下都需要实现多个goroutine之间的协调和通信。Context则是在这种情况下的一种很便捷的选择。
Context的主要注意点:
Context是线程安全的。
Context可以被析构。
Context.Value返回的是一个空interface类型,需要类型断言。
2. Context使用示例
2.1 在Context中传递值
Context的最常见用途就是在多个goroutine之间传递请求的上下文信息。context包提供了WithValue操作,该操作可以将key-value键值对存储到Context变量中。
package main
import (
"context"
"fmt"
)
type key int
const myKey key = 0
func main() {
ctx := context.WithValue(context.Background(), myKey, "Hello World")
value := ctx.Value(myKey)
fmt.Println(value)
}
在这个示例中,我们初始化了context,然后通过WithValue函数设置了一组key-value键值对,key的类型是一个自定义的类型myKey,value是"Hello World"字符串。最后我们通过ctx.Value方法查询了这个值。
2.2 在Context中取消操作
在编写复杂应用程序时,有时候我们需要在一组并行goroutine中发送取消信号。Context类支持这个需求,我们可以通过上下文的CancelFunc完成这个操作。
package main
import (
"context"
"fmt"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
}
}()
cancel()
select {}
}
在这个示例中,我们使用context.WithCancel函数设置了一个上下文。然后我们在新的goroutine中监听ctx.Done方法返回的信号,如果信号被触发,则输出ctx.Err()返回的内容。接着使用cancel函数发送了取消信号。
2.3 Context同步
Context可以实现多个goroutine之间的同步操作。我们可以使用WithCancel或者WithTimeout等操作中的一种,来构建一个Context,而后通过WaitGroup,来等待relateGoroutine完成相应的任务,一直到任务完成为止。
package main
import (
"context"
"fmt"
"sync"
"time"
)
func task(ctx context.Context, wg *sync.WaitGroup) error {
defer wg.Done()
for {
select {
default:
fmt.Println("Working...")
time.Sleep(100 * time.Millisecond)
case <-ctx.Done():
return ctx.Err()
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go task(ctx, &wg)
}
wg.Wait()
}
在这个示例中,我们使用WithTimeout函数设置了一个上下文,并限定了最长运行时间为3秒。然后我们通过WaitGroup实现多个goroutine的同步,并让所有goroutine都执行完task函数。
3. Context小结
通过本文的讲解,我们了解了Context在协调goroutine之间的通信和请求上下文中的有用性。我们可以通过WithValue、WithCancel、WithTimeout等方法实现context的相关操作。Context的运用可以大大提高代码的简洁度和可读性。