Golang协程之了解管道的缓存能力

简介: Golang协程之了解管道的缓存能力

Golang协程之了解管道的缓存能力

我们之前讲过,当使用make建立管道时,第二个参数为零,就证明这个管道是无缓存能力的管道。只要没人写就永远读不出来,只要没人读就永远写不进去。例如:

ch := make(chan int,0)

管道的缓冲区能被初始化为指定的缓冲区容量。 如果为零,或者省略了大小,则该通道是无缓冲的。

如果将第二个参数改为8(这里可以为任意大小),这就说明缓存能力为8,即使不读,也能写入8个元素。

package main

import (
    "fmt"
    "time"
)

func main() {
    //The channel's buffer is initialized with the specified buffer capacity.
    //If zero, or the size is omitted, the channel is unbuffered.
    ch := make(chan int,0)

    go func() {
        ch <- 123
        fmt.Println("数据已写入")
    }()

    go func() {
        time.Sleep(2*time.Second)
        x:= <- ch
        fmt.Println("数据已读出",x)
    }()

    time.Sleep(5*time.Second)
    fmt.Println("Game Over!")
}

这段代码在运行过程中,由于一条协程在写入管道缓冲区,另一条协程在读取管道的缓冲区,但是读取管道缓冲区的那条协程会sleep 两秒,所以在前两秒另一条写入管道缓冲区的协程也不能写入。

如果让写入管道缓冲区的那条协程sleep两秒,那么前两秒另一条读取管道缓冲区的协程也不能读取数据。

如果一个缓冲区大小为3的管道,写入4个值,那么第4个值就写入不了,运行结果是这样的:

写入1
写入2
写入3

下面我们来看一看管道内的元素个数及它的缓存能力吧:

package main

import (
    "fmt"
    "time"
)

func main101() {
    ch := make(chan int,3)

    go func() {
        ch <- 1
        fmt.Println("写入1")
        ch <- 2
        fmt.Println("写入2")
        ch <- 3
        fmt.Println("写入3")
        //管道的缓冲区已经存满,不能再写入!
        ch <- 4
        fmt.Println("写入4")
    }()
    time.Sleep(5 * time.Second)
}

func main() {
    ch := make(chan int,3)
    fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch));

    ch <- 123
    fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch));
    ch <- 123
    fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch));
    ch <- 123
    fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch));
    
}

运行结果是

元素的个数为 0 缓存能力为 3
元素的个数为 1 缓存能力为 3
元素的个数为 2 缓存能力为 3
元素的个数为 3 缓存能力为 3
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    E:/main.go:36 +0x4e5

Process finished with exit code 2

我们可以看到管道的缓存能力是没有变化的,但是存入的元素个数是在变化的。

我们可以看到这里出现了死锁,这里主协程永远无法继续执行。

我们再来了解一下管道的有关知识。

据了解,管道是建立在堆上面的。使用make函数返回的是指针,这就是为什么我们能够在函数之间传递管道,不需要传递指向管道的指针。

ch := make(chan int,0)

使用make创建一个管道只能传输同一类型的数据,建立一个管道时需要指定一个数据类型,不允许通过一个管道传输多种类型的数据。

目录
相关文章
|
3月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
145 4
Golang语言之管道channel快速入门篇
|
3月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
101 4
|
4月前
|
Go 调度 开发者
[go 面试] 深入理解进程、线程和协程的概念及区别
[go 面试] 深入理解进程、线程和协程的概念及区别
|
1月前
|
存储 安全 测试技术
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
128 29
|
5月前
|
Java Go 调度
GO 协程
GO 协程
46 0
|
1月前
|
Go 计算机视觉
在Golang高并发环境中如何进行协程同步?
在此示例中,使用互斥锁来保护对共享计数器变量 c 的访问,确保并发的 HTTP 请求不会产生数据竞争。
48 3
|
1月前
|
负载均衡 算法 Go
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
|
2月前
|
安全 Go 调度
探索Go语言的并发模式:协程与通道的协同作用
Go语言以其并发能力闻名于世,而协程(goroutine)和通道(channel)是实现并发的两大利器。本文将深入了解Go语言中协程的轻量级特性,探讨如何利用通道进行协程间的安全通信,并通过实际案例演示如何将这两者结合起来,构建高效且可靠的并发系统。
|
3月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
80 4
Golang语言goroutine协程篇
|
2月前
|
中间件 Go 数据处理
应用golang的管道-过滤器架构风格
【10月更文挑战第1天】本文介绍了一种面向数据流的软件架构设计模式——管道-过滤器(Pipe and Filter),并通过Go语言的Gin框架实现了一个Web应用示例。该模式通过将数据处理流程分解为一系列独立的组件(过滤器),并利用管道连接这些组件,实现了模块化、可扩展性和高效的分布式处理。文中详细讲解了Gin框架的基本使用、中间件的应用以及性能优化方法,展示了如何构建高性能的Web服务。
90 0