Go中如何使用context实现跨goroutine通信

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的运用可以大大提高代码的简洁度和可读性。

后端开发标签