2

Go 并发消息队列 channel

 2 years ago
source link: https://wnanbei.github.io/post/go-%E5%B9%B6%E5%8F%91%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97-channel/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Go 并发消息队列 channel

Channel 实际上是类型化消息的队列,它有以下特性:

  • 只能传输一种类型的数据。
  • 所有的类型都可以用于通道,空接口 interface{} 也可以。
  • 先进先出 FIFO 的结构。
  • 引用类型,所以使用 make() 函数来给它分配内存。

声明一个无缓冲的 Channel

var ch1 chan int
ch2 := make(chan int)

有缓冲 Channel

ch := make(chan int, 1)
ch := make(chan int)
defer close(ch)

ch <- 5

阻塞:

  • nil 通道发送数据会被阻塞。
  • 向无缓冲 channel 写数据,如果读协程没有准备好会阻塞。
  • 向有缓冲 channel 写数据,如果缓冲已满会阻塞。

panic:

  • 向已 closed 的 channel 写数据会 panic。

有缓冲的 channel,如果发送的时候,刚好有等待接收的协程,那么会直接交换数据。

v, ok := <- ch
v := <-ch

ok 可以用来判断 channel 是否已经关闭,如果关闭该值为 true ,此时 v 接收到的是 channel 类型的零值。

<- ch 可以单独调用获取通道的(下一个)值,当前值会被丢弃,但是可以用来验证,所以以下代码是合法的:

if <- ch != 1000{
    ...
}

阻塞:

  • nil 通道接收数据会被阻塞。

  • 从无缓冲 channel 读数据,如果写协程没有准备好,会阻塞。

  • 从有缓冲 channel 读数据,如果缓冲为空,会阻塞。

读取的 channel 如果被关闭,并不会影响正在读的数据,它会将所有数据读取完毕,并不会立即就失败或者返回零值。

通道在创建时都是双向的,但是我们可以声明单向的通道,在传递参数时用来限制使用者对通道的操作:

func source(ch chan<- int){ // 单向入队列
    for { ch <- 1 }
}

func sink(ch <-chan int) { // 单向出队列
    for { <-ch }
}

特性:

  • 只接收的通道 <-chan T 是无法关闭的。

for-range 可以用来便利读取 channel 中的数据:

ch := make(chan int, 1)

for val := range ch {
    fmt.Println(val)
}
  • 如果 channel 已经被关闭,它还是会继续执行,直到所有值被取完,然后退出执行。

  • 如果通道没有关闭,但是 channel 没有可读取的数据,它则会阻塞在 range 这句位置,直到被唤醒。

  • 如果 channel 是 nil,那么同样符合我们上面说的的原则,读取会被阻塞,也就是会一直阻塞在 range 位置。

select

select case 语句可以方便的对通道进行操作,每次执行 select 语句,将会执行所有的 case 语句,判断是否有表达式能够执行。

也就是说,select case 语句能同时监控多个通道,当有通道离开堵塞状态,就可以获知并执行相应的代码。

ch := make(chan int)
q := make(chan int)

for {
    select {
    case ch <- x:
        x, y = y, x+y
        break
    case <-q:
        fmt.Println("quit")
        return
    }
}
  1. select 只要有默认语句,就不会被阻塞,换句话说,如果没有 default,然后 case 又都不能读或者写,则会被阻塞。
  2. nil 的 channel,不管读写都会被阻塞。
  3. select 不能够像 for-range 一样发现 channel 被关闭而终止执行,所以需要结合 multi-valued assignment 来处理。
  4. 如果同时有多个 case 满足了条件,会使用伪随机选择一个 case 来执行。
  5. select 语句如果不配合 for 语句使用,只会对 case 表达式求值一次。
  6. 每次 select 语句的执行,是会扫码完所有的 case 后才确定如何执行,而不是说遇到合适的 case 就直接执行了。

channel 在使用完毕以后需要关闭,一般的建议是谁写入,谁负责关闭。

如果有多个写协程的 channel 需要关闭,可以使用额外的 channel 来标记,也可以使用 sync.Once 或者 sync.Mutex 来处理。

ch := make(chan int, 1)
defer close(ch)

注:closed 的 channel,再次关闭会 panic。

空 struct

有时我们需要将 channel 作为一个信号传输的管道,此时管道中的内容并不重要,只需要知道有信号传输过来即可。

此时可以使用空 struct 作为传输的数据类型,因为空 struct 类型的内存占用大小为 0。即:

var c1 chan struct{}
c1 <- struct{}{}

Recommend

  • 80
    • www.choupangxia.com 6 years ago
    • Cache

    Java并发阻塞队列之ArrayBlockingQueue

    JUC简介 在 Java 5.0 提供了java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类,用于定义类似于线程的自定义子系统,包括线程池,异步IO和轻量级任务框架;还提供了设计用于多线程上下文中的Collection实...

  • 49
    • www.tuicool.com 4 years ago
    • Cache

    并发编程之并发队列

    一、并发队列 在并发队列上JDK提供了两套实现, 一个是以ConcurrentLinkedQueue为代表的高性能队列非阻塞, 一个是以BlockingQueue接口为代表的阻塞队列,无论哪种都继承自Queue。 1、阻塞队列与非阻塞...

  • 20

    要深入了解java并发知识,AbstractQueuedSynchronizer(AQS)是必须要拿出来深入学习的,AQS可以说是贯穿了整个JUC并发包,例如ReentrantLock,CountDownLatch,CyclicBarrier等并发类都涉及到了AQS。接下来就对AQS的实现原理进行分析。

  • 4
    • dayarch.top 3 years ago
    • Cache

    分分钟搞定Java 并发队列

    日拱一兵|Java|Spring Boot|Java并发编程|最新干货分享 从来没有真正的绝境| ...

  • 23
    • my.oschina.net 3 years ago
    • Cache

    Java并发队列与容器

    Java并发队列与容器 - 大数据学习与分享的个人空间 - OSCHINA - 中文开源技术交流社区 【前言:无论是大数据从业人员还是Java从业人员,掌握Java高并发和多线程是必备技能之一。本文主要阐述Java并发包下的阻塞队列和并发容器,其实研读过大数...

  • 14

    什么是队列 队列是一种 先进先出的特殊线性表,简称 FIFO。特殊之处在于只允许在一端插入,在另一端删除 进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列 图片队列在程序设计中使用...

  • 5

    ArrayBlockingQueue实际应用场景 之前在某公司做过一款情绪识别的系统,这套系统通过调用摄像头接口采集人脸信息,将采集的人脸信息做人脸识别和情绪分析,最终经过一定的算法将个人情绪数据转化具体行为指标值。其中采集图片的部分就...

  • 4
    • yusank.github.io 2 years ago
    • Cache

    [GoIM] 实现异步并发 worker 队列

    记录实现一个异步并发 worker 队列的过程 2022-04-01  约 2805 字   预计阅读 6 分钟 原文链接: 实现异步并发 worker 队列

  • 9
    • blog.51cto.com 1 year ago
    • Cache

    Java并发编程学习7-阻塞队列

    Java并发编程学习7-阻塞队列 推荐 原创 Huazie 2022-10-18 15:21:21...

  • 4

    JUC简介转自 极客时间 1. JUC简介 从JDK1.5起,Java API 中提供了java.util.concurrent(简称JUC)包,在此包中定义了并发编程中很常用 的工具,比如:线程池、阻塞队列、同步器、原子类等等。JUC是 JSR 166 标准规范的一个实...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK