• golang应用专题 - channel


    channel相关

    channel基础

    1、channel的初始化

    ch := make(chan int64, 10): 创建一个可发送int64类型数据的channel,其容量为10

    1. make() 创建出的channel是一个引用类型,当对channel进行复制和函数传递时,也只是拷贝了改channel的引用
    2. channel可以使用 == 进行比较。当两个channel引用底层数据结构是同一个时,返回true

    2、channel的关闭

    close(ch): 表示channel被关闭

    1. 发送。发送消息给一个已关闭的channel,会触发panic
    2. 接收。channel关闭后依然可以接收channel中的消息,当channel中无消息时,返回对应数据类型的零值
    3. 试图重复关闭一个channel会触发panic异常
    4. 试图关闭一个nil值的channel会歘panic异常

    3、channel的数据统计

    len(ch): channel队列中已有元素的个数
    cap(ch): channel队列的容量

    无缓冲的channel

    当初始化channel不指定通道容量(或指定容量为0)时,该通道为无缓冲channel;

    1、无缓冲channel的特性

    一个无缓冲channel的发送操作将导致发送者goroutine的阻塞,直到另一个goroutine在相同的channel上执行接收操作
    同理接收者阻塞,直到另一个goroutine发送

    2、无缓冲channel的用途

    1. 同步操作。如事件A(goroutineA)必须在事件B(goroutineB)之前完成,则在goroutineA中完成时间A后发送无缓冲channel,goroutineB中接收到统一channel的消息再执行事件B
    2. Pipeline. 可以使用多个无缓冲channel连接多个goroutine,形成一个管道(pipeline)。

    3、goroutine泄露

    func testGoroutineLeak() {
    	ch := make(chan int64)
    	go func() { ch <- 64 }()
    	go func() { ch <- 52 }()
    	go func() { ch <- 41 }()
    	<-ch
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当无缓冲channel的发送者goroutine数量和接受者goroutine数量不一致时,会导致较多一方的goroutine阻塞,且无法自动回收(goroutine不会自动被回收),造成goroutine泄露

    单方向的channel

    1. 双向channel可以隐式转换为单方向channel
    2. 反之不可

    有缓冲的channel

    当初始化channel时指定通道容量,该通道为有缓冲的channel;

    有缓冲的通道可以一定程度上解决上述“无缓冲通道”引发的goroutine泄露问题

    channel的常用操作示例

    1、使用for range读channel

    场景:需要轮询channel中的数据
    优点:当channel关闭时自动退出循环,无需额外判断channel是否关闭;
    用法:

    for x := range ch {
    do_something(x)
    }

    2、使用_, ok判断channel是否关闭

    场景:读channel,但不确定channel是否关闭
    优点:可以通过ok值明确判断channel是否关闭,不受channel类型本身0值的影响
    用法:

    if x, ok := <- chan {
    do_something(x)
    }

    3、使用select处理多个channel

    场景:

    1. 需要读取/写入多个通道时,不因一个通道的阻塞影响另一个通道的写入
    2. 需要给读取/写入操作增加超时时间

    4、消息广播

    场景:协程退出时,通知所有子协程退出。关闭通道close(ch)后,所有子协程可以感知通道关闭并自动退出

    channel底层源码实现

    传送门

    channel面试题

    同一个协程里,对一个无缓冲的channel同时发送和接收数据有什么问题?有缓冲呢?

    同一个协程是串行的,无法同时做“发送”和“接收”两个事情,只能先发后收,或者先收后发。

    1. 无缓冲:会造成goroutine阻塞,协程对一个无缓冲的channel发送(或者接收)消息会阻塞;
    2. 有缓冲:正常执行。
      • 但是没必要?同一个协程的通信直接函数调用或者串行代码逻辑

    channel的应用场景?

    1. 协程间的数据通信
      • 多个协程通过发送和读取同一个channel来实现消息传递
    2. 并发控制
      • channel可以做消息分流,增加并行消费者(kafka消费者场景)
    3. 消息队列
      • 本地的生产消费模型中,可用作消息队列
    4. 同步操作
      • 无缓冲的channel可以用作对同步操作的控制,在前执行的事件需要执行完发送channel,在后执行的事件接收到channel的消息后再执行
    5. 管道PIPELINE
      • 多个无缓冲的channel可连接多个goroutine,实现数据流管道;如:
        • goA产生数据0、1、2 给chanA
        • goB接收chanA,执行平方操作,给chanB
        • goC接收chanB, 执行两数相加操作;最终可实现0 + 1*1 + 2*2 + 3*3...这种场景
    6. 消息广播
      • channel发送特定的消息,接收者接收消息执行约定好的行为
      • 可以通过close(ch)广播事件,下游接收ch消息的协程可感知channel关闭,后执行对应操作

    channel和锁的对比?

    channel是线程安全的,使用channel可以解决数据并发问题;但是channel解决并发问题的场景是“数据的流动性”,数据在动,channel不动(提供了串行获取流动数据的能力)

    锁mutex也可以解决并发访问资源的问题;但是mutex更多解决“静态数据”的问题,即数据不动,某段时间控制只给一个协程访问

  • 相关阅读:
    TP-Link家用路由器上网与防蹭网
    【回归预测-lssvm】基于粒子群算法优化最小二乘支持向量机lssvm实现数据回归预测附matlab代码
    【21天算法学习】折半查找
    21天学习挑战赛——Python爬虫 requests库
    Android Jetpack之DataBinding+ViewModel+LiveData+Room
    计算机物联网控制11月9日第五章-重要5.3数控技术基础 *涉及到了真正的控制算法* 5.4PID控制算法
    Camera BSP之GPIO/I2C/PMIC简介
    《面试八股文》之 JVM 20卷
    力扣每日一题70:爬楼梯
    【leetcode】【2022/9/6】828. 统计子串中的唯一字符
  • 原文地址:https://blog.csdn.net/qq_39679639/article/details/125463719