Golang的Channel基本定义和用法

本文介绍了Golang中Channel的基本概念和用法,包括无缓冲Channel的同步特性,有缓冲Channel的工作原理,如何关闭Channel以及在关闭后的影响。此外,还讨论了利用range操作Channel和使用select进行多Channel监控的方法。通过实例解析,帮助读者深入理解Golang的并发通信机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.无缓冲Channel

package main

import (
	"fmt"
	"time"
)

// 子goroutine,主goroutine结束,子也结束
func NewTask() {
	i := 0
	for {
		i++
		fmt.Println("new Goroutine: i =", i)
		time.Sleep(1 * time.Second)
	}
}

func main() {
	//定义一个无缓冲的channel
	c := make(chan int)

	go func() {
		defer fmt.Println("go goroutine 结束")
		fmt.Println("go goroutine 正在进行....")
		c <- 66 // 将66写的chan中
	}()

	// 从channel中读取数据,复制给num
	num := <-c
	fmt.Println("num is ", num)
}

// 结果:
go goroutine 正在进行....
go goroutine 结束
num is  66

注意:

  • 有没有可能main方法先执行完,sub go还没发送给c信息?

不会,当main从chan中拿不到数据,会阻塞等待

  • sub go把66放到chan中,main还没来得及读,defer会执行吗?

不会,因为是无缓冲channel,子sub go会阻塞等待main 获取数据

在这里插入图片描述

2.有缓冲Channel

package main

import (
	"fmt"
	"time"
)

// 子goroutine,主goroutine结束,子也结束
func NewTask() {
	i := 0
	for {
		i++
		fmt.Println("new Goroutine: i =", i)
		time.Sleep(1 * time.Second)
	}
}

func main() {
	//定义一个有缓冲的channel
	c := make(chan int, 3)

	fmt.Println("c的length =", len(c), "c的cap =", cap(c))

	go func() {
		defer fmt.Println("go goroutine 结束")
		for i := 0; i < 4; i++ {
			c <- i // 将i写的chan中
			fmt.Println("go goroutine 正在进行....,发送的元素:", i, "length =", len(c), "cap = ", cap(c))
		}
	}()

	time.Sleep(3 * time.Second)
	// 从channel中读取数据,复制给num
	for i := 0; i < 3; i++ {
		num := <-c
		fmt.Println("num is ", num)
	}

	fmt.Println("main 结束 ")

}

// 结果:
go goroutine 正在进行....,发送的元素: 0 length = 1 cap =  3
go goroutine 正在进行....,发送的元素: 1 length = 2 cap =  3
go goroutine 正在进行....,发送的元素: 2 length = 3 cap =  3
num is  0
num is  1
num is  2
main 结束 
go goroutine 正在进行....,发送的元素: 3 length = 3 cap =  3
go goroutine 结束

注意:

  • 当go goroutine中channel的元素满了,将会被阻塞,直到获取完一个num即继续运行
  • 当channel为空,从里面取数据也会阻塞

3.关闭channel

  1. 关闭channel不用像关闭文件一样,经常去关闭
  2. 关闭channel后无法再向channel中发送数据(引发panic error)
  3. 关闭channel后,可以继续从channel中获取数据
  4. 对于nil channel,一定发送阻塞错误,记住一定要make
    感觉兴趣的小伙伴可以加好友一起交流!!

4.Channel与range的使用

for data := range c {
	fmt.Println(data)
}

5.Channel与select的使用

单个流程下go只能监控一个Channel状态,select可以完成多个Channel监控状态

package main

import (
	"fmt"
)

func feibonicii(c, quit chan int) {
	x, y := 1, 1
	for {
		select {
		case c <- x: //如果c可写,将x写入c中
			x = y
			y = x + y
		case <-quit: // 如果quit可读,则sub go已执行完任务
			fmt.Println("quit....")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)

	// sub go
	go func() {
		for i := 0; i < 16; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()

	// main go
	feibonicii(c, quit)
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值