• Golang 并发 与 context标准库


    文章链接:https://mp.weixin.qq.com/s/FJLH4o7Y1TG9I0seiNwR_w

         https://maiyang.me/post/2018-02-12-how-to-correctly-use-context.context-in-golang/

    context是一个很好的解决多goroutine下通知传递和元数据的Go标准库。由于Go中的goroutine之间没有父子关系,因此也不存在子进程退出后的通知机制。多个goroutine协调工作涉及 通信,同步,通知,退出 四个方面:

    通信:chan通道是各goroutine之间通信的基础。注意这里的通信主要指程序的数据通道。
    同步:可以使用不带缓冲的chan;sync.WaitGroup为多个gorouting提供同步等待机制;mutex锁与读写锁机制。
    通知:通知与上文通信的区别是,通知的作用为管理,控制流数据。一般的解决方法是在输入端绑定两个chan,通过select收敛处理。这个方案可以解决简单的问题,但不是一个通用的解决方案。
    退出:简单的解决方案与通知类似,即增加一个单独的通道,借助chan和select的广播机制(close chan to broadcast)实现退出。

    但由于Go之间的goroutine都是平等的,因此当遇到复杂的并发结构时处理退出机制则会显得力不从心。因此Go1.7版本开始提供了context标准库来解决这个问题。他提供两个功能:退出通知和元数据传递。他们都可以传递给整个goroutine调用树的每一个goroutine。同时这也是一个不太复杂的,适合初学Gopher学习的一段源码。

    工作机制

    第一个创建Context的goroutine被称为root节点:root节点负责创建一个实现Context接口的具体对象,并将该对象作为参数传递至新拉起的goroutine作为其上下文。下游goroutine继续封装该对象并以此类推向下传递。

    package main

    import (
    "context"
    "time"
    )

    func main() {
    // withcancel func
    ctxCal, canlce := context.WithCancel(context.Background())

    // withtimeout func
    ctxTim, _ := context.WithTimeout(ctxCal, time.Second*3)

    go work(ctxTim, "work1")
    //time.Sleep(10*time.Second)

    // withvalue func
    ctxVal := context.WithValue(ctxTim, "key", "custom value")
    go workWithValue(ctxVal, "work3")
    time.Sleep(1*time.Second)
    canlce()
    time.Sleep(2*time.Second)
    }

    func workWithValue(ctx context.Context, name string) {
    for {
    select {
    case <-ctx.Done():
    println(name, "get message to quit")
    return
    default:
    value := ctx.Value("key").(string)
    println(name, "is running with value", value)
    time.Sleep(time.Second)

    }
    }
    }

    func work(ctx context.Context, name string) {
    for {
    select {
    case <-ctx.Done():
    println(name, "get message to quit")
    return
    default:
    println(name, "is running")
    time.Sleep(time.Second)
    }
    }
    }

    work3 is running with value custom value
    work1 is running
    work1 is running
    work3 get message to quit
    work1 get message to quit

    可以看到,当ctxb因超时而退出之后,会通知由他包装的所有子goroutine(ctxc),并通知退出。各context的关系结构如下:

  • 相关阅读:
    ZooKeeper的工作原理
    redis 数据类型详解 以及 redis适用场景场合
    nginx负载均衡原理
    Java中缓存的介绍
    Java中接口的作用
    json与xml的区别
    最经典40个多线程问题总结
    Java线程 : 线程同步与锁
    dbcp与c3p0的区别
    Linux常见命令
  • 原文地址:https://www.cnblogs.com/smallleiit/p/12394208.html
Copyright © 2020-2023  润新知