Goroutine之context上下文

一、context上下文简介

context简单的理解就是上下文,它可以进行不同协程之间的通信,所以也就包含了上下文的环境等变量信息。有下面三种用法:

  • WithCancel 通过该方法可以达到一个协程在某一时刻控制另一个协程的退出
  • WithDeadline 通过该方法可以在一个协程在指定时间点控制另一个协程的退出
  • WithTimeout 通过该方法进行超时设置,一旦超时,相应的协程就会退出

二、使用方法

1、WithCancel 

 WithCancel返回一个带着Done通道的context副本以及一个cancel函数,这个带着Done通道的副本在cancel函数被调用或者父context的Done通道被关闭时,它就会关闭。

package main

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

var wg sync.WaitGroup

func getInfo(ctx context.Context) {
    defer wg.Done()
    for {
        time.Sleep(time.Second)
        select {
        case <-ctx.Done(): // 检查cancel是否到时间执行
            fmt.Println("获取信息结束!")
            return
        default:
            fmt.Println("获取信息!")
        }
    }
}

func main() {
    wg.Add(1)
    ctx, cancel := context.WithCancel(context.Background())
    go getInfo(ctx)
    time.Sleep(time.Second * 5)
    cancel() // 5s后执行cancel函数
    wg.Wait()

}

/*
获取信息!
获取信息!
获取信息!
获取信息!
获取信息结束!
*/

2、WithDeadline 

WithDeadline返回一个带着截至日期的context副本,如果到达了截至日期,那么这个副本的Done通道的副本在cancel函数被调用或者父context的Done通道被关闭时,它就会关闭。

package main

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

var wg sync.WaitGroup

func getInfo(ctx context.Context) {
    defer wg.Done()
    for {
        time.Sleep(time.Second)
        select {
        case <-ctx.Done(): // 到时间会自动调用cancel函数,结束协程函数
            fmt.Println("获取信息结束!")
            return
        default:
            fmt.Println("获取信息!")
        }
    }
}

func main() {
    wg.Add(1)
    d := time.Now().Add(time.Second * 5)
    ctx, _ := context.WithDeadline(context.Background(), d) // 如果没有返回cancel函数也是可行的,只要在规定的d时间内就自动结束传入ctx的函数
    go getInfo(ctx)
    wg.Wait()

}

/*
获取信息!
获取信息!
获取信息!
获取信息!
获取信息结束!
*/

3、WithTimeout

WithTimeout返回一个带着超时时间的context副本,如果到达了时间,那么这个Done通道的副本在cancel函数被调用或者父context的Done通道被关闭时,它就会关闭。

如果显式调用cancel函数,那么如果未在超时时间之前也可以结束相应的协程。

package main

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

var wg sync.WaitGroup

func getInfo(ctx context.Context) {
    defer wg.Done()
    for {
        time.Sleep(time.Second)
        select {
        case <-ctx.Done(): // 到时间会自动调用cancel函数,结束协程函数
            fmt.Println("获取信息结束!")
            return
        default:
            fmt.Println("获取信息!")
        }
    }
}

func main() {
    wg.Add(1)
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
    go getInfo(ctx)
    defer cancel() // 超时之后释放资源
    wg.Wait()

}

/*
获取信息!
获取信息!
获取信息!
获取信息!
获取信息结束!
*/

 

上一篇:qt-编码问题解答


下一篇:Go-waitGroup的那些事