参考文档:

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. KingbaseES 原生XML系列五--XML关系表函数

    KingbaseES 原生XML系列五--XML关系表函数(QUERY_TO_XML,TABLE_TO_XML,XMLTABLE) XML的简单使其易于在任何应用程序中读写数据,这使XML很快成为数据 ...

  2. KingbaseESV8R6等待事件之LWLock buffer_mapping

    等待事件含义 当会话将数据块与共享缓冲池中的缓冲区关联时,会发生此等待事件. 类似Oracle cbc闩锁的是一种Kingbase的轻量级锁lwlock,这个锁的名字在不同数据库版本中可能有所不同,我 ...

  3. SpaceDesk怎么连接平板/PC(提高生产力,扩展副屏)

    1.下载安装 分为安卓端和PC端,两个设备都需要安装对应的软件. SpaceDesk官网 https://link.zhihu.com/?target=http%3A//spacedesk.net/ ...

  4. Scala 特质(Trait)

    1 package chapter06 2 3 object Test13_Trait { 4 def main(args: Array[String]): Unit = { 5 val studen ...

  5. GeminiDB Cassandra接口新特性FLASHBACK发布:任意时间点秒级闪回

    本文分享自华为云社区<GeminiDB Cassandra接口新特性FLASHBACK发布:任意时间点秒级闪回>,作者: GaussDB 数据库. 技术背景 数据库作为现代信息系统的核心组 ...

  6. ASCII编码的全面介绍

    1. ASCII编码的定义和历史 ASCII(American Standard Code for Information Interchange)是一种用于将文本字符转换为数字编码的标准,最初由美国 ...

  7. OpenHarmony Meetup 2023 广州站圆满举办,城市巡回全面启航

      "OpenHarmony正当时--技术开源"OpenHarmony Meetup 2023城市巡回活动,旨在通过meetup线下交流形式,解读OpenHarmony作为下一代智 ...

  8. 【开源三方库】bignumber.js:一个大数数学库

    OpenHarmony(OpenAtom OpenHarmony简称"OpenHarmony")三方库,是经过验证可在OpenHarmony系统上可重复使用的软件组件,可帮助开发者 ...

  9. Seaborn结构化图形绘制(FacetGrid)

    结构化图形绘制(FacetGrid) 可实现多行多列个性化绘制图形. sns.FacetGrid( data, row=None, col=None, hue=None, col_wrap=None, ...

  10. MogDB-opengauss中的聚集与分组操作

    MogDB/opengauss 中的聚集与分组操作 COUNT:对结果集中的元组数量进行计数,如果是 COUNT(*),那么会统计所有元组(包括 NULL 值)的数量,如果是 COUNT(colnam ...