前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Go - chan 通道

Go - chan 通道

作者头像
新亮
发布于 2019-08-06 07:01:48
发布于 2019-08-06 07:01:48
65200
代码可运行
举报
文章被收录于专栏:新亮笔记新亮笔记
运行总次数:0
代码可运行

概述

原来分享的基础语法的时候,还未分享过 chan 通道,这次把它补上。

chan 可以理解为队列,遵循先进先出的规则。

在说 chan 之前,咱们先说一下 go 关键字。

在 go 关键字后面加一个函数,就可以创建一个线程,函数可以为已经写好的函数,也可以是匿名函数。

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
    fmt.Println("main start")

    go func() {
        fmt.Println("goroutine")
    }()

    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
main end

为什么没有输出 goroutine ?

首先,我们清楚 Go 语言的线程是并发机制,不是并行机制。

那么,什么是并发,什么是并行?

并发是不同的代码块交替执行,也就是交替可以做不同的事情。

并行是不同的代码块同时执行,也就是同时可以做不同的事情。

举个生活化场景的例子:

你正在家看书,忽然电话来了,然后你接电话,通话完成后继续看书,这就是并发,看书和接电话交替做。

如果电话来了,你一边看书一遍接电话,这就是并行,看书和接电话一起做。

说回上面的例子,为什么没有输出 goroutine ?

main 函数是一个主线程,是因为主线程执行太快了,子线程还没来得及执行,所以看不到输出。

现在让主线程休眠 1 秒钟,再试试。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
    fmt.Println("main start")

    go func() {
        fmt.Println("goroutine")
    }()

    time.Sleep(1 * time.Second)

    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
goroutine
main end

这就对了。

接下来,看看如何使用 chan 。

声明 chan

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 声明不带缓冲的通道
ch1 := make(chan string)

// 声明带10个缓冲的通道
ch2 := make(chan string, 10)

// 声明只读通道
ch3 := make(<-chan string)

// 声明只写通道
ch4 := make(chan<- string)

注意:

不带缓冲的通道,进和出都会阻塞。

带缓冲的通道,进一次长度 +1,出一次长度 -1,如果长度等于缓冲长度时,再进就会阻塞。

写入 chan

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ch1 := make(chan string, 10)

ch1 <- "a"

读取 chan

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val, ok := <- ch1
// 或
val := <- ch1

关闭 chan

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
close(chan)

注意:

  • close 以后不能再写入,写入会出现 panic
  • 重复 close 会出现 panic
  • 只读的 chan 不能 close
  • close 以后还可以读取数据

示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
    fmt.Println("main start")
    ch := make(chan string)
    ch <- "a" // 入 chan
    go func() {
        val := <- ch // 出 chan
        fmt.Println(val)
    }()
    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
fatal error: all goroutines are asleep - deadlock!

What ? 这是为啥,刚开始就出师不利呀?

因为,定义的是一个无缓冲的 chan,赋值后就陷入了阻塞。

怎么解决它?

声明一个有缓冲的 chan。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
    fmt.Println("main start")
    ch := make(chan string, 1)
    ch <- "a" // 入 chan
    go func() {
        val := <- ch // 出 chan
        fmt.Println(val)
    }()
    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
main end

为啥没有输出 a , 和前面一样,主线程执行太快了,加个休眠 1 秒钟,再试试。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
    fmt.Println("main start")
    ch := make(chan string, 1)
    ch <- "a" // 入 chan
    go func() {
        val := <- ch // 出 chan
        fmt.Println(val)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
a
main end

这就对了。

再看一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
    fmt.Println("main start")
    ch := make(chan string)
    go func() {
        ch <- "a" // 入 chan
    }()
    go func() {
        val := <- ch // 出 chan
        fmt.Println(val)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
a
main end

再看一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func producer(ch chan string) {
    fmt.Println("producer start")
    ch <- "a"
    ch <- "b"
    ch <- "c"
    ch <- "d"
    fmt.Println("producer end")
}

func main() {
    fmt.Println("main start")
    ch := make(chan string, 3)
    go producer(ch)

    time.Sleep(1 * time.Second)
    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
producer start
main end

带缓冲的通道,如果长度等于缓冲长度时,再进就会阻塞。

再看一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func producer(ch chan string) {
    fmt.Println("producer start")
    ch <- "a"
    ch <- "b"
    ch <- "c"
    ch <- "d"
    fmt.Println("producer end")
}

func customer(ch chan string) {
    for {
        msg := <- ch
        fmt.Println(msg)
    }
}

func main() {
    fmt.Println("main start")
    ch := make(chan string, 3)
    go producer(ch)
    go customer(ch)

    time.Sleep(1 * time.Second)
    fmt.Println("main end")
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main start
producer start
producer end
a
b
c
d
main end

就到这吧。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 新亮笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
go语言学习-并发编程
1.After函数:起到定时器的作用,指定的纳秒后会向返回的channel中放入一个当前时间(time.Time)的实例。
solate
2019/07/22
6140
Golang之旅23-通道channel
在goroutine并发执行的时候,需要在函数和函数之间进行通信。Go语言并发模式CSP(communicating Sequents Processes),通过通信共享内存。
皮大大
2021/03/02
3340
Go语言学习——channel的死锁其实没那么复杂
  协程(goroutine)算是Go的一大新特性,也正是这个大杀器让Go为很多路人驻足欣赏,让信徒们为之欢呼津津乐道。
JackieZheng
2019/07/11
1K0
go-并发
Go语言的并发通过 goroutine 实现。 goroutine 类似于线程,属于用户态的线程,我们可以根据需要创建成千上万个 goroutine 并发工作。 goroutine 是由Go语言的运行时(runtine)调度完成,而线程是由操作系统调度完成的。
新人小试
2020/03/27
7000
go-并发
【实践】Golang的goroutine和通道的8种姿势
如果说php是最好的语言,那么golang就是最并发的语言。 支持golang的并发很重要的一个是goroutine的实现,那么本文将重点围绕goroutine来做一下相关的笔记,以便日后快速留恋。
辉哥
2019/08/18
1.5K0
Golang 基础之基础语法梳理 (二)
单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义,channel就是它们之间的连接。
帽儿山的枪手
2022/03/20
6900
Golang 基础之基础语法梳理 (二)
Go编写工具教程第一课 高并发端口扫描
今天我们一起来学习下如何用GO 编写一个高并发端口扫描工具,本教学文章持续连载,后面会接连着实现主机发现,漏洞探测,远程执行,暴力破解等等的教学,有兴趣的师傅可关注公众号回复加群一起讨论~
WgpSec
2021/02/04
2.5K0
Go编写工具教程第一课 高并发端口扫描
Golang中的channel解析与实战
channel也叫通道,类似于一个队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。channel一般分为无缓存通道和有缓存通道,无缓存通道指缓存为0的channel,有缓存通道指缓存大于0的channel
素履coder
2022/10/05
5940
Golang中的channel解析与实战
Go语言并发编程总结
Golang :不要通过共享内存来通信,而应该通过通信来共享内存。这句风靡在Go社区的话,说的就是 goroutine中的 channel ....... 他在go并发编程中充当着 类型安全的管道作用。 1、通过golang中的 goroutine 与sync.Mutex进行 并发同步 import( "fmt" "sync" "runtime" ) var count int =0; func counter(lock * sync.Mutex){ lock.Lock
李海彬
2018/03/23
1.3K0
深入学习Golang—channel
Channel 1. 概述 “网络,并发”是Go语言的两大feature。Go语言号称“互联网的C语言”,与使用传统的C语言相比,写一个Server所使用的代码更少,也更简单。写一个Server除了网络,另外就是并发,相对python等其它语言,Go对并发支持使得它有更好的性能。 Goroutine和channel是Go在“并发”方面两个核心feature。 Channel是goroutine之间进行通信的一种方式,它与Unix中的管道类似。 Channel声明: ChannelType = ( "chan
李海彬
2018/03/21
1.3K0
《Go语言入门经典》10~12章读书笔记
在Go语言中,一种约定是在调用可能出现问题的方法或函数时,返回一个类型为错误的值。这意味着如果出现问题,函数通常不会引发异常,而让调用者决定如何处理错误。
跑马溜溜的球
2020/12/07
5380
Golang学习笔记之并发.协程(Goroutine)、信道(Channel)
简单的理解一下,并发就是你在跑步的时候鞋带开了,你停下来系鞋带。而并行则是,你一边听歌一边跑步。 并行并不代表比并发快,举一个例子,当文件下载完成时,应该使用弹出窗口来通知用户。而这种通信发生在负责下载的组件和负责渲染用户界面的组件之间。在并发系统中,这种通信的开销很低。而如果这两个组件并行地运行在 CPU 的不同核上,这种通信的开销却很大。因此并行程序并不一定会执行得更快。 Go 原生支持并发。在Go中,使用 Go 协程(Goroutine)和信道(channel)来处理并发。
李海彬
2018/12/27
1.4K0
Golang学习笔记之并发.协程(Goroutine)、信道(Channel)
「一闻秒懂」你了解goroutine和channel吗?
大家都知道进程是操作系统资源分配的基本单位,有独立的内存空间,线程可以共享同一个进程的内存空间,所以线程相对轻量,上下文切换开销也小。虽然线程已经比较轻量了,但还是占近1M的内存,而今天介绍的有“轻量级线程”之称的Goroutine,可以小至几十K甚至几K,切换的开销更小。
平也
2020/04/16
4970
「一闻秒懂」你了解goroutine和channel吗?
go进阶(2) -深入理解Channel实现原理
Go的并发模型已经在https://guisu.blog.csdn.net/article/details/129107148 详细说明。
黄规速
2023/02/27
3280
go进阶(2) -深入理解Channel实现原理
《快学 Go 语言》第 12 课 —— 神秘的地下通道
不同的并行协程之间交流的方式有两种,一种是通过共享变量,另一种是通过队列。Go 语言鼓励使用队列的形式来交流,它单独为协程之间的队列数据交流定制了特殊的语法 —— 通道。
老钱
2018/12/24
4030
《快学 Go 语言》第 12 课 —— 神秘的地下通道
7.Go编程快速入门学习
描述: 反射是指在程序运行期对程序本身进行访问和修改的能力。即支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
全栈工程师修炼指南
2022/09/29
6950
GoLang协程与通道---上
作为一门 21 世纪的语言,Go 原生支持应用之间的通信(网络,客户端和服务端,分布式计算)和程序的并发。程序可以在不同的处理器和计算机上同时执行不同的代码段。Go 语言为构建并发程序的基本代码块是 协程 (goroutine) 与通道 (channel)。他们需要语言,编译器,和runtime的支持。Go 语言提供的垃圾回收器对并发编程至关重要。
大忽悠爱学习
2022/08/23
7810
GoLang协程与通道---上
深入浅出Go语言通道chan类型
通道(chan)类似于一个队列,特性就是先进先出,多用于goruntine之间的通信
闫同学
2023/10/14
2180
Golang中的管道(channel) 、goroutine与channel实现并发、单向管道、select多路复用以及goroutine panic处理
管道(channel)是 Go 语言中实现并发的一种方式,它可以在多个 goroutine 之间进行通信和数据交换。管道可以看做是一个队列,通过它可以进行先进先出的数据传输,支持并发的读和写。
周小末天天开心
2023/10/16
6530
Golang中的管道(channel) 、goroutine与channel实现并发、单向管道、select多路复用以及goroutine panic处理
如何使用 Go 更好地开发并发程序,纯干货!
Go 语言的并发特性是其一大亮点,今天我们来带着大家一起看看如何使用 Go 更好地开发并发程序?
aoho求索
2021/03/16
5300
如何使用 Go 更好地开发并发程序,纯干货!
相关推荐
go语言学习-并发编程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文