参考文档:

https://www.liwenzhou.com/posts/Go/14_concurrence/

http://www.5lmh.com/并发编程/channel.html

示例一:

package main

import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
wg.Add(2)
go nobufChannel() //不带缓冲区的初始化
go bufChannel() //有缓冲区的通道
wg.Wait()
} //不带缓冲区的初始化
func nobufChannel() {
defer wg.Done()
channel1 := make(chan int)
go func() {
x := <-channel1
fmt.Println("channel里取出的数字:", x)
close(channel1)
}()
channel1 <- 10
fmt.Println("10存入channel") } //有缓冲区的通道
func bufChannel() {
defer wg.Done()
channel2 := make(chan int, 1) //指定了只能放一个数
channel2 <- 10
fmt.Println("10 发送到通道用bufChannel")
//channel2 <- 20 //todo 指定了只能放一个数,取出后,才能继续向通道里存入数据
//fmt.Println("20 发送到通道用bufChannel")
ch2 := <-channel2
fmt.Println("取出bufChannel中的数据,", ch2)
}

示例二:

package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var once sync.Once
func main() {
fmt.Println("我是返回值")
a := make(chan int, 100)
b := make(chan int, 100)
wg.Add(3)
go setValue(a)
go getValue(a, b)
go getValue(a, b)
for ret :=range b{
fmt.Println(ret) //循环打印b通道中的数据
}
wg.Wait()
}
func setValue(a chan int) {
defer wg.Done()
//循环的存入通道中
for i := 1; i <= 100; i++ {
a <- i
}
close(a)
} func getValue(a, b chan int) {
defer wg.Done()
for {
v,ok:= <-a
if !ok {
break
}
b <- v //循环读出a通道中的数据,再的存入b通道中
}
once.Do(func(){close(b)})
}

close()

可以通过内置的close()函数关闭channel(如果你的管道不往里存值或者取值的时候一定记得关闭管道)

package main

import "fmt"

/*
1.对一个关闭的通道再发送值就会导致panic。
2.对一个关闭的通道进行接收会一直获取值直到通道为空。
3.对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。
4.关闭一个已经关闭的通道会导致panic。 */ func main() {
a := make(chan int, 2)
a <- 10
a <- 20
close(a)
//for k := range a {
// fmt.Println(k)
//} v, ok := <-a
fmt.Println(v, ok) //10 true
v, ok = <-a
fmt.Println(v, ok) //20 true
v, ok = <-a
fmt.Println(v, ok) //0 false
v, ok = <-a
fmt.Println(v, ok) //0 false
}

如何优雅的从通道循环取值

当通过通道发送有限的数据时,我们可以通过close函数关闭通道来告知从该通道接收值的goroutine停止等待。当通道被关闭时,往该通道发送值会引发panic,从该通道里接收的值一直都是类型零值。那如何判断一个通道是否被关闭了呢?

我们来看下面这个例子:

package main

import "fmt"

// channel 练习
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
// 开启goroutine将0~100的数发送到ch1中
go func() {
for i := 0; i < 100; i++ {
ch1 <- i
}
close(ch1)
}()
// 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中
go func() {
for {
i, ok := <-ch1 // 通道关闭后再取值ok=false
if !ok {
break
}
ch2 <- i * i
}
close(ch2)
}()
// 在主goroutine中从ch2中接收值打印
for i := range ch2 { // 通道关闭后会退出for range循环
fmt.Println(i)
}
}

从上面的例子中我们看到有两种方式在接收值的时候判断通道是否被关闭,我们通常使用的是for range的方式。

实现斐波那契数列

//实现斐波那契数列:1 1 2 3 5 8
package main import "fmt" //此时的ch只写,quit只读
func fibonacci(ch chan<- int, quit <-chan bool) {
x, y := 1, 1
for {
//监听channel数据的流动
select {
case ch <- x:
x, y = y, x+y
case flag := <-quit: //没数据时一直处于阻塞状态
fmt.Println("flag=", flag)
return //不能用break,因为只跳出select这一层
}
}
}
func main() {
//创建双向通道,没有缓冲的
ch := make(chan int) //数字通信
quit := make(chan bool) //程序是否结束 //生产者,从channel读取内容
//新建协程
go func() {
for i := 0; i < 8; i++ {
num := <-ch //只读,没数据时,处于阻塞状态
fmt.Println("num=", num)
}
//可以停止
quit <- true //写
}() //生产者,产生数字,写入channel
fibonacci(ch, quit)
}

通道总结

channel常见的异常总结,如下图:

注意:关闭已经关闭的channel也会引发panic。

Go语言基础之并发 goroutine chan的更多相关文章

  1. GO学习-(18) Go语言基础之并发

    Go语言基础之并发 并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因. Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微 ...

  2. Go语言基础之并发

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因. Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天) ...

  3. GO_11:GO语言基础之并发concurrency

    并发Concurrency 很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已.不过话说回来,每个实例 4-5KB的 ...

  4. GO语言基础之并发concurrency

    并发Concurrency 很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已.不过话说回来,每个实例 4-5KB的 ...

  5. Golang语言系列-11-goroutine并发

    goroutine 并发 概念 package main import ( "fmt" "time" ) /* [Go语言中的并发编程 goroutine] [ ...

  6. Go语言中的并发编程

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因. Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天) ...

  7. Go语言系列之并发编程

    Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(宏观上并行,微观上并发). 并行:同一时刻执行多个任务(宏观和微观都是并行). Go语言的并发通过goroutine实现.gorout ...

  8. Go语言基础之函数

    Go语言基础之函数 函数是组织好的.可重复使用的.用于执行指定任务的代码块.本文介绍了Go语言中函数的相关内容. 函数 Go语言中支持函数.匿名函数和闭包,并且函数在Go语言中属于“一等公民”. 函数 ...

  9. Go语言基础之1--标识符、关键字、变量和常量、数据类型、Go的基本程序结构、Golang的特性

    一.前言 当我们项目较为简单时,我们在src目录下新建一个该项目目录,里面存放源码文件即可,见下图: 当我们一个项目较为复杂时,我们可以在src目录下新建一个该项目目录,在针对该项目不同模块创建不同目 ...

  10. Go 语言基础

    Go 语言基础 特点 常用命令 go run 直接运行, 不会生成可执行文件 go build 生成可执行文件, 推荐 加分特点 UTF-8编码 高并发: go 关键字 管道: pipe := mak ...

随机推荐

  1. 初学 FSMC - 外扩SRAM(三)

    1. FSMC相关函数 //FSMC初始化 void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct); //FSMC ...

  2. ET介绍——强大的MongoBson库

    强大的MongoBson库 后端开发,统计了一下大概有这些场景需要用到序列化: 对象通过序列化反序列化clone 服务端数据库存储数据,二进制 分布式服务端,多进程间的消息,二进制 后端日志,文本格式 ...

  3. Mybatis-Plus框架的BaseMapper的insert方法和自定义mapper里面的insert方法会用哪个

    在Mybatis-Plus框架中,当一个接口继承了BaseMapper接口,并且绑定了一个xml文件时,如果这个接口和xml文件中都定义了相同的方法,那么在调用该方法时,会优先调用xml文件中的方法, ...

  4. Git 删除 .gitignore 生成之前上传的文件

    清除缓存 git rm -r --cached . git add . 提交记录 git commit -m "chore: 清除缓存." git push

  5. 两个专栏帮你搞定【图像拼接(image stitching)】

    [图像拼接论文精读]专栏:图像拼接论文精读 [图像拼接源码精读]专栏:图像拼接论文源码精读 前言 图像拼接(image stitching)是计算机视觉中的高级图像处理手段,是一个小众方向,研究的人很 ...

  6. OpenHarmony创新赛 | 赛事宣讲会日期重磅官宣!为你带来超详尽的赛事攻略

      最近接到很多小伙伴私信提问,比如如何报名开放原子开源大赛OpenAtom OpenHarmony(简称:"OpenHarmony")创新赛?有哪些赛题可以报名参赛?现在,赛事宣 ...

  7. C语言 02 安装

    C 语言的编译器有很多,其中最常用的是 GCC,这里以安装 GCC 为例. Windows 这里以 Windows 11 为例 官方下载地址:https://www.mingw-w64.org/ 选择 ...

  8. 鸿蒙智联生态产品《接入智慧生活App开发指导》(官方更新版)

    原文:https://mp.weixin.qq.com/s/BDC-12aiZz2EhtjYLR7QIg,点击链接查看更多技术内容. 在HarmonyOS Connect生态产品应用开发过程中,很多开 ...

  9. ​CentOS防火墙操作命令 ​

    CentOS防火墙操作命令 1.查看防火墙服务状态 systemctl status firewalld.service 或者查看防火墙的状态: 1 firewall-cmd --state 2.开启 ...

  10. button submit你以为你阻止了默认事件?

    前言 先解决掉一个误区: 很多人写button的时候,就这样写: <button><botton> 你认为就是默认的submit的时候,这时候就可能出问题了. 当然之所以你没有 ...