Golang学习 goroutine协程及channel管道

本文详细介绍了Go语言中无缓冲和带缓冲区的管道在协程间数据传递中的行为,展示了阻塞与非阻塞的情况。
摘要由CSDN通过智能技术生成

先看看无缓冲区域的管道。如下图,

第一步,左边协程产生了一个数据,欲将数据放入管道

第二步,左边协程成功将数据放入管道,但是右边协程不来取,他被锁在管道里了

第三步,右边管道来取数据了

第四步,两个协程完成握手传递数据

第五步,右边管道成功拿到数据

第六步,协程阻塞会被取消,各自执行接下来的流程

代码如下:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	var chanS = make(chan string) //定义一个管道变量,不带缓冲区的

	go func(a int, b int) {
		defer fmt.Println("goroutine结束了")
		for i := 0; i <= 20; i++ {
			fmt.Printf("%d goroutine a+b=%d\n", i, a+b)
		}

		chanS <- "channel data" //将goroutine生成的数据传送至管道里,此时会阻塞协程,直到主线程读取管道里的数据。如果主线程不读取管道里的数据的话,协程会一直卡在这里,不会执行下面的语句

		func() {
			fmt.Printf("内部函数执行\n")
			runtime.Goexit() //如果在内部要退出协程的话要用  runtime.Goexit();
		}()
		fmt.Println("test2") //这个语句不会被执行,因为在上个内部函数里退出了协程
		return               //使用return退出当前协程
		fmt.Println("go")
	}(10, 20)

	gets := <-chanS //从管道里取出数据,此时会阻塞主线程,直到管道里有数据
	fmt.Println("channel data is", gets)
	fmt.Println("main goroutine") //由于上面阻塞了线程,所以这里会最后执行
	time.Sleep(time.Second)
}

接下来看一下带有缓冲区域的channel

package main

import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	chanS := make(chan string, 3) //声明一个容量为3的管道

	fmt.Println("管道长度为:", len(chanS), "容量为:", cap(chanS))

	go func() {
		defer fmt.Println("子goroutine结束了")
		for i := 0; i < 4; i++ {
			chanS <- "chan " + strconv.Itoa(i)
			fmt.Println("子goroutine(", strconv.Itoa(i), ")正在执行,当前长度为:", len(chanS), "容量为:", cap(chanS))
		}
	}()
	time.Sleep(2 * time.Second) //休眠2秒,效果更明显
	for i := 0; i < 4; i++ {
		str := <-chanS
		fmt.Println("主goroutine(", str, ")拿到数据,当前长度为:", len(chanS), "容量为:", cap(chanS))
	}
	fmt.Println("主goroutine结束了")
}

channel关闭的方法

close(chanS)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值