二十五、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 := <-c
	fmt.Println(msg)
}
func showWriter(c chan<- string) {
	c <- "hello world"
}

func showReaderAndWriter(c chan string) {
	msg := <-c
	fmt.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)
			return
		case 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退出了通道

相关推荐
恋恋风辰3 小时前
QT系列教程(16) 定时器事件
开发语言·qt·命令模式
Tttian6224 小时前
Spring
java·后端·spring
南山不太冷4 小时前
Spring(4)——响应相关
java·后端·spring
拓端研究室TRL6 小时前
R软件线性模型与lmer混合效应模型对生态学龙类智力测试数据层级结构应用
开发语言·r语言
于慨7 小时前
计算机考研C语言
c语言·开发语言·数据结构
GGGGGGGGGGGGGG.7 小时前
使用dockerfile创建镜像
java·开发语言
请为小H留灯7 小时前
Python中很常用的100个函数整理
开发语言·python
winyh57 小时前
基于Golang的微服务——Consul
微服务·golang·consul
达斯维达的大眼睛8 小时前
QT小项目-简单的记事本
开发语言·qt
轩宇^_^8 小时前
C++ 类与对象的实际应用案例详解
开发语言·c++