go并发编程-路线总结2

context

上下文信息传递,还提供了超时(Timeout)和取消(Cancel)的机制

1个接口

context.Context是个接口,定义了4个方法

  • Deadline:返回 被取消的截止日期
  • Done:返回一个 Channel 对象。在 Context 被取消时,此 Channel 会被 close
  • Err:返回 Done 被 close 的原因
  • Value:返回此 ctx 中和指定的 key 相关联的 value

4个具体实现

  • emptyCtx
    • 本质是个整形(int),对接口的实现只是简单的返回nil,false
  • chanelCtx
    • 可取消的context
  • timerCtx
    • 在cancelCtx基础上,封装了一个定时器和一个截止时间
  • valCtx
    • 给context附加一个键值对信息

6个函数

  • Background
    • 返回一个非 nil 的、空的 Context
    • 一般用在主函数、初始化、测试以及创建根Context 的时候
    • 类型是 emptyCtx
  • TODO
    • 返回一个非 nil 的、空的 Context
    • 当你不清楚是否该用 Context,或者目前还不知道要传递一些什么上下文信息的时候,就可以使用这个方法。
    • 类型是 emptyCtx
  • WithCancel
    • 返回 parent 的副本,只是副本中的 Done Channel 是新建的对象
    • 类型是 cancelCtx。
  • WithDeadline
    • 返回 parent 的副本,并且设置了一个截止时间
    • 类型是 timerCtx。
  • WithTimeout
    • 和 WithDeadline 一样,只不过设置的是超时时间
    • 类型为是timerCtx
  • WithValue
    • 基于 parent Context 生成一个新的 Context,保存了一个 key-value 键值对
    • 类型是 valueCtx

Atomic原子操作

在其它线程看来,原子操作要么执行完了,要么还没有执行

方法

atomic 操作的对象是一个地址

  • Add:给地址中的值增加某个值
  • CAS:比较地址内的值,相同才替换
  • Swap:替换地址中的值,返回旧值
  • Load:取出地址中的值,原子操作
  • Store:往地址存值,原子操作
  • Value 类型:原子地存取对象类型,但也只能存取,不能 CAS 和 Swap

使用 atomic 和直接内存操作的区别

  • atomic 提供内存屏障的功能,保证赋值的数据完整性、可见性,一旦一个核更新了该地址的值,其它处理器总是能读取到它的最新值
  • 内存,撕裂写(两个指令,执行一个,其他人看到更新一半的数据)

Channel

通过通信共享内存,而不是通过共享内存而实现通信

基本用法

  • 发送数据
  • 接收数据
  • 关闭chan

结构体

  • qcount:循环队列元素的数量
  • dataqsiz:循环队列的大小。
  • buf:循环队列的指针。
  • elemtype 和 elemsize:chan 中元素的类型和 size。
  • sendx:处理发送数据的指针在 buf 中的位置。
  • recvx:处理接收请求时的指针在 buf 中的位置。
  • recvq:接收者等待队列。
  • sendq:发送者等待队列。
  • lock:互斥锁

常见错误

  • panic
    • close 为 nil 的 chan;
    • send 已经 close 的 chan;
    • close 已经 close 的 chan。
  • 内存泄露
    • 缺少接收端或者发送端,或者提前结束接收端或者发送端没有close channel

应用场景

  • 消息交流:生产者-消费者
  • 消息传递:Goroutine数据交换
  • 信号通知:Goroutine信号传递
  • 任务编排:让goroutine按照顺序并发
    • Or-Done模式:
      • 信号通知模式
      • 多个任务,只要一个任务执行完,就获得信号
    • 扇入模式:多个输入源 Channel 、一个目的 Channel 输出
    • 扇出模式:一个输入源 Channel,多个目的 Channel输出
    • Stream:把 Channel 当作流式管道使用的方式
    • Map-Reduce:一种处理数据的方式

Semaphore(信号量)

一个变量加一些并发控制的能力(最简单的信号量)

实现

  • 初始化信号量:设定初始的资源的数量
  • P 操作:将信号量的计数值减去 1
  • V 操作:将信号量的计数值加 1

类型

  • 二进位信号量:互斥的功能(要么是 0,要么是 1)
  • 计数信号量:限制多个goroutine同时访问某个资源的数量

Go 官方扩展库信号量的实现semaphore.Weighted

方法

  • Acquire:相当于 P 操作。先入先出,第一个等待者获取够资源,才会到下一个
  • Release:相当于 V 操作
  • TryAcquire:尝试获取 n 个资源,但是它不会阻塞,要么成功获取 n 个资源,返回 true,要么一个也不获取,返回 false。

结构体

  • size int64 // 最大资源数
  • cur int64 // 当前已被使用的资源
  • mu sync.Mutex // 互斥锁,对字段的保护
  • waiters list.List // 等待队列

常见错误

  • 请求了资源,但是忘记释放它
  • 释放了从未请求的资源

使用错误

  • Release 时,传递一个比请求到的数量大的数值, panic。
  • Release 时,传递一个负数,会导致资源永久被持有。
  • Acquire,请求的资源数比最大的资源数大,可能永远被阻塞(依赖ctx的状态返回,否则一直等待)。

SingleFlight

作用

  • 在处理多个goroutine 同时调用同一个函数的时候,只让一个 goroutine 去调用这个函数,等到这个goroutine 返回结果的时候,再把结果返回给这几个同时调用的 goroutine,这样可以减少并发调用的数量。
  • 并发请求合并成一个请求

结构体

  • mu sync.Mutex // protects m
  • m map[string]*call // lazily initialized

方法

  • Do
    • 执行一个函数,并返回函数执行的结果
    • 提供一个 key,对于同一个 key,在同一时间只有一个在执行
  • DoChan
    • 类似 Do 方法,只不过是返回一个 chan,等 fn 函数执行完,就能从 chan 中接收返回结果
  • Forget
    • 忘记这个 key。之后这个 key 请求会执行 f,而不是等待前一个未完成的 fn 函数的结果。

循环栅栏 CyclicBarrier

作用

  • 一组 goroutine 彼此等待,到达一个共同的执行点(都在栅栏前等待,全部到齐,抬起栅栏放行)。
  • 可以被重复使用,所以叫循环栅栏

初始化方法

  • New :指定循环栅栏参与者的数量
  • NewWithAction:额外提供一个函数,可以在每一次到达执行点的时候执行一次

CyclicBarrier接口

  • Await(ctx context.Context) error // 等待所有参与者到达,被ctx.Done()中断,返回ErrBrokenBarrier
  • Reset() // 重置到初始化状态。如果当前有等待者,那么它们会返回ErrBrokenBarrier
  • GetNumberWaiting() int // 返回当前等待者的数量
  • GetParties() int // 参与者的数量
  • IsBroken() bool // 循环栅栏是否处于中断状态
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值