go ctx

go ctx

December 18, 2020
Go
Ctx

ctx #

1.why

goroutine号称百万之众,互相之间盘根错节,难以管理控制。为此,必须提供一种机制来管理控制它们。

各自为战 #

package main

import (
    "fmt"
    "time"
)

func main() {
    // start first
    go func() {
        fmt.Println(1)
    }()

    // start second
    go func() {
        fmt.Println(2)
    }()

    time.Sleep(time.Second)
}

万法归一 #

package main

import (
    "fmt"
    "sync"
)

func main() {
    wg := new(sync.WaitGroup)

    // start first
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println(1)
    }()

    // start second
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println(2)
    }()

    wg.Wait()
}

可以看到使用waitgroup可以控制多个goroutine必须互相等待,直到最后一个完成才会全部完成。

明修栈道暗度陈仓 #

package main

import (
    "fmt"
)

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    // start first
    go func() {
        fmt.Println(1)
        <-ch2
        ch1 <- 1
    }()

    ch3 := make(chan int)

    // start second
    go func() {
        fmt.Println(2)
        ch2 <- 2
        <-ch1

        // escape
        ch3 <- 3
    }()

    n := <-ch3
    fmt.Println(n)
}

使用chan的话,可以实现goroutine之间的消息同步

2.what

Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.

– 提供标准库context,定义了Context类型,带有限期、取消信息和其它请求域里的跨API边界和进程间的值。

3.how

package main

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

func main() {
    var n time.Duration = 2

    now := time.Now()
    ctx, cancel := context.WithDeadline(context.Background(), now.Add(time.Second*n))
    _ = cancel

    fmt.Println(now)

    // start first
    go func(ctx context.Context) {
        select {
        case <-ctx.Done():
        }
        fmt.Println(time.Now(), 1)
    }(ctx)

    // start second
    go func(ctx context.Context) {
        select {
        case <-ctx.Done():
        }
        fmt.Println(time.Now(), 2)
    }(ctx)

    time.Sleep(time.Second * (n - 1))
    fmt.Println(time.Now())
 
    // 一秒钟之后取消的话,两个goroutine会在取消后马上执行;如果等到时间到期了,就会在两秒后执行;
    // cancel()
    // fmt.Println(time.Now())

    time.Sleep(time.Second * (n + 1))
}

4.others