当前位置: 首页 > news >正文

二十五、go语言的通道

目录

一、收发通信

二、将通道作为参数传递(读、写、读写)

三、select

1、先收到消息的先执行

2、一直没有收到消息退出通道

3、不知道何时退出情况下退出通道


go语言中的goroutine可以看成线程,但是又不能看成和其它语言一样的线程,因为在go语言中,goroutine之间的通信和其它语言不一样,例如如果在java中多条线程访问一个内存中数据在访问前需要进行加锁避免其它线程进入进行修改,本质上是通过共享了内存进行通信。而在go中是不一样的,在go中是“不要通过共享内存进行通信,而是通过通信来共享内存”

一、收发通信

import ("fmt""time"
)func receiver(c chan string) {for msg := range c {fmt.Println(msg)}
}
func main() {message := make(chan string, 2)message <- "hello"message <- "world"close(message)fmt.Println("push two message to channel")time.Sleep(time.Second * 2)receiver(message)
}

结果在2s中后输出

hello
world
解释

上述案例中 receiver函数接收了一个通道为string值的参数,并且进行循环输出

main方法中,mak(chan string,2)声明创建长度为2的通道

message <- "" 往通道内存入消息

close关闭通道意味着不可以再通过这个通道发送消息

调用receiver并传入message参数

二、将通道作为参数传递(读、写、读写)

在参数中<-在chan左边意味着可读,在右边意味着可写,没有意味着可读可写

func showReader(c <-chan string) {msg := <-cfmt.Println(msg)
}
func showWriter(c chan<- string) {c <- "hello world"
}func showReaderAndWriter(c chan string) {msg := <-cfmt.Println(msg)c <- "hello world"
}

在reader函数中,c是什么我们只能输出什么

在writer函数中,c是什么我们可以修改

在readerAndWriter函数中,c是什么我们可以输出什么也可以指定c是什么

三、select

1、先收到消息的先执行
func ping(c chan int) {time.Sleep(time.Second * 3)c <- 1
}
func ping2(c chan<- int) {time.Sleep(time.Second * 2)c <- 2
}
func main() {channel := make(chan int)channel2 := make(chan int)go ping(channel)go ping2(channel2)select {case msg := <-channel:fmt.Println(msg)case msg := <-channel2:fmt.Println(msg)}
}

结果:

2

解释L

在select中最先收到消息的执行后续代码,当创建两个ping方法时,ping sleep了3秒,ping2 sleep了2秒所以先执行了ping2

2、一直没有收到消息退出通道

当一直没有收到消息可以使用case <-time.After(time.Second * 3):

import ("fmt""time"
)func ping(c chan int) {time.Sleep(time.Second * 5)c <- 1
}
func ping2(c chan<- int) {time.Sleep(time.Second * 4)c <- 2
}
func main() {channel := make(chan int)channel2 := make(chan int)go ping(channel)go ping2(channel2)select {case msg := <-channel:fmt.Println(msg)case msg := <-channel2:fmt.Println(msg)case <-time.After(time.Second * 3):fmt.Println("timeout")}}
3、不知道何时退出情况下退出通道
import ("fmt""time"
)func sender(c chan string) {t := time.NewTicker(1 * time.Second)for {c <- "hello world"<-t.C}
}
func main() {messages := make(chan string)stop := make(chan bool)go sender(messages)go func() {time.Sleep(2 * time.Second)fmt.Println("time up")stop <- true}()for {select {case status := <-stop:fmt.Println(status)returncase msg := <-messages:fmt.Println(msg)}}
}

结果:

hello world
hello world
hello world
time up
true


解释:

 创建了一个sender方法,使用time.NewTicker(1 * time.Second),每一秒往通道中传递一次值

t := time.NewTicker(1 * time.Second)
for {c <- "hello world"<-t.C
}

在for循环中执行 

case msg := <-messages:fmt.Println(msg)

在接收到消息后执行,那么如果在没有手动终止程序的话就会一直执行

所以创建一个退出通道,当接收到true值时进行return,退出通道

case status := <-stop:fmt.Println(status)return

在同时并发执行一个func,并让这个程序sleep 2秒后,在给通道stop值为true

go func() {time.Sleep(2 * time.Second)fmt.Println("time up")stop <- true}()

所以在第一次并发调用

go sender(messages)

执行了一次

fmt.Println(msg)

此时func开始sleep 2秒,所以又执行了两次,当stop为ture时进行了return退出了通道


http://www.mrgr.cn/news/12362.html

相关文章:

  • django orm的Q和~Q的数据相加并不一定等于总数
  • 一款MySQL数据库实时增量同步工具,能够监听MySQL二进制日志(Binlog)的变动(附源码)
  • 图片去噪及边缘检测
  • 8月27日笔记
  • ubuntu64位配置兼容32位程序手册
  • 基于STM32开发的智能家居语音控制系统
  • 创建索引对象pandas.Index()
  • SpringBoot调用通义千问
  • 谷歌浏览器与edge哪个好用
  • 天宝TBCTrimble Business Center中文版本下载安装使用介绍
  • Vue -- 总结 01
  • 电机foc学习渠道已开放,欢迎各位加入
  • JavaScript:js;知识回顾;笔记分享
  • WPF ToolkitMVVM IOC IServiceConllection
  • 内存函数memcpy和memmove
  • 基于SSM的垃圾分类管理系统的设计与实现 (含源码+sql+视频导入教程+论文)
  • JSP 常用指令精简介绍
  • C++基础知识(三)
  • 第一次运行Neo4J
  • 力扣455-分发饼干(java题解)