Go_channel(管道)

Posted yzg-14

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go_channel(管道)相关的知识,希望对你有一定的参考价值。

技术图片

 1. 计算阶乘

package main

import (
	"fmt"
	_ "time"
	"sync"
)

//需求:现在要计算 1-200 的各个数的阶乘,并且把各个数的阶乘放入到map中。
//最后显示出来。要求使用goroutine完成

//思路
//1. 编写一个函数,来计算各个数的阶乘,并放入到 map中.
//2. 我们启动的协程多个,统计的将结果放入到 map中
//3. map 应该做出一个全局的.

var (
	myMap = make(map[int]int, 10)
	//声明一个全局的互斥锁
	//lock 是一个全局的互斥锁,
	//sync 是包: synchornized 同步
	//Mutex : 是互斥
	lock sync.Mutex
)

//test 函数就是计算 n!, 让将这个结果放入到 myMap
func test(n int) {

	res := 1
	for i := 1; i <= n; i++ {
		res *= i
	}

	//这里我们将 res 放入到myMap
	//加锁
	lock.Lock()
	myMap[n] = res //concurrent map writes?
	//解锁
	lock.Unlock()
}

func main() {

	//我们这里开启多个协程完成这个任务[20个]
	for i := 1; i <= 20; i++ {
		go test(i)
	}
	
	//休眠10秒钟【第二个问题 】
	//time.Sleep(time.Second * 5)

	//这里我们输出结果,变量这个结果
	lock.Lock()
	for i, v := range myMap {
		fmt.Printf("map[%d]=%d
", i, v)
	}
	lock.Unlock()

}

为什么输出结果需要加锁

技术图片

2. 为什么需要channel

技术图片

2.1 队列

技术图片

 技术图片

 2.2 管道声明

 技术图片

技术图片

package main

import (
	"fmt"
)

func main() {

	//演示一下管道的使用
	//1. 创建一个可以存放3个int类型的管道
	var intChan chan int
	intChan = make(chan int, 3)

	//2. 看看intChan是什么
	fmt.Printf("intChan 的值=%v intChan本身的地址=%p
", intChan, &intChan)
	//intChan 的值=0xc000094000 intChan本身的地址=0xc00008e018

	//3. 向管道写入数据
	intChan <- 10
	num := 211
	intChan <- num
	intChan <- 50
	//如果从channel取出数据后,可以继续放入
	<-intChan //取出来扔了,不要
	intChan <- 98 //注意点, 当我们给管写入数据时,不能超过其容量

	//4. 看看管道的长度和cap(容量)
	fmt.Printf("channel len= %v cap=%v 
", len(intChan), cap(intChan)) //channel len= 3 cap=3

	//5. 从管道中读取数据
	var num2 int
	num2 = <-intChan
	fmt.Println("num2=", num2) //num2= 211
	fmt.Printf("channel len= %v cap=%v 
", len(intChan), cap(intChan)) //channel len= 2 cap=3

	//6. 在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告deadlock(死锁错误)
	num3 := <-intChan
	num4 := <-intChan

	num5 := <-intChan //已经没有了,再取就会报错
	//all goroutines are asleep - deadlock!

	fmt.Println("num3=", num3, "num4=", num4 , "num5=", num5) //num3= 50 num4= 98

}

注意事项

技术图片

3. 案例

技术图片

技术图片

技术图片

技术图片

技术图片

package main
import (
	"fmt"
)

type Cat struct {
	Name string
	Age int
}

func main() {

	//定义一个存放任意数据类型的管道 3个数据
	//var allChan chan interface{}
	allChan := make(chan interface{}, 3)

	allChan<- 10
	allChan<- "tom jack"
	cat := Cat{"小花猫", 4}
	allChan<- cat

	//我们希望获得到管道中的第三个元素,则先将前2个推出
	<-allChan
	<-allChan

	newCat := <-allChan //从管道中取出的Cat是什么?

	fmt.Printf("newCat=%T , newCat=%v
", newCat, newCat)
	//newCat=main.Cat , newCat={小花猫 4}

	//下面的写法是错误的!编译不通过
	//fmt.Printf("newCat.Name=%v", newCat.Name) //在编译的层面上认为newCat是接口,接口是没有字段的
	//使用类型断言
	a := newCat.(Cat)
	fmt.Printf("newCat.Name=%v", a.Name) //newCat.Name=小花猫


}

 

以上是关于Go_channel(管道)的主要内容,如果未能解决你的问题,请参考以下文章

Go_channel

[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础

使用 FFmpeg 通过管道输出视频片段

r 计算管道的步骤(基本片段)

15种Python片段去优化你的数据科学管道

如何在降价表的代码语句中转义管道字符?