您现在的位置是:首页 >其他 >GO语言小锤硬磕.二十二 管道(channel)网站首页其他

GO语言小锤硬磕.二十二 管道(channel)

shockWaveGo 2023-06-02 12:00:03
简介GO语言小锤硬磕.二十二 管道(channel)

1.认识channel

        管道本质是一个队列(先进先出

        管道是线程安全的(自带锁)

        管道解决协程中资源同步问题

2.声明和初始化Channel

package main
import "fmt"
func main(){
//1.声明管道  var 变量名 chan 数据类型    
    var mych chan int
//2.初始化管道    make(chan 数据类型,管道容量) 
    //管道和切片、字典一样make开辟存储空间后才能使用
    //管道和切片、字典一样是引用类型
    mych = make(chan int,3)
//3.查看管道的长度和容量
    fmt.println("长度是",len(mych),"容量是",cap(mych))
//4.管道写入数据
    mych<- 666
//5.取出管道中的数据
    num := <-mych
//注意
    1.管道中只能存放声明的数据类型。
    2.主线程中管道中已经没有数据,并且检测不到其他线程写入数据,再取会报错。
    3.主线程中管道数据已满,再写入也会报错。
}

3.管道的关闭和遍历

package main
import "fmt"
func main(){
//1.创建一个管道
    mych := make(chan int,3)
//2.写入数据
    mych<- 666
    mych<- 777
    mych<- 888
//3.关闭管道,关闭后只能读不能写
    close(mych)
//4.使用for range 遍历管道。使用前必须先关闭管道否则会报deadlock的错误
    //管道的遍历会弹出管道数据,长度会减少
    for value := range mych{
        fmt.Println(value)
    } 

//5.其他方式 ok-idiom模式读取管道,判断管道是否关闭,如果关闭会返回false给ok
    for{
        if num,ok:= <-mych; !ok{
            break;
        }else{
            fmt.Println(num)
        }
    }
//6.误区
    管道正常读取一次,内容会弹出,长度(len(mych))会减少1
    //for i:=0; i<len(mych); i++ {   //不正确


}

4.Channel阻塞现象

        单独在主线程中操作管道,写满了会报错,没有数据去获取也会报错

        只要在协程中操作管道过,写满了就会阻塞,没有数据去获取也会阻塞

5.使用Channe实现生产者消费者

package main
import(
    "fmt"
    "math/rand"
    "time"
)
//定义缓冲区
var mych = make(chan int,5)
var exitch = make(chan bool,1)

//定义生产者
func producer(){
    rand.Seed(time.Now().UnixNano())
    for i:=0;i<10;i++{
        num:=rand.Intn(100)
        fmt.Println("生产者生产",num)
        //写入管道
        mych<-num
    }
    //生产完毕关闭管道
    close(mych)
    fmt.Println("生产者停止生产")
}
//定义消费者
func consumer(){
    //不断从管道中获取数据,直到管道关闭
    for{
        if num,ok := <-mych;!ok{
            break
        }else{
            fmt.Println("消费了",num)
        }
    }
    fmt.Println("消费者停止消费")
    exitch<-true

}
func main(){
    go producer()
    go consumer()
    fmt.Println("exitch之前代码")
    <-exitch
    fmt.Println("exitch之后代码")
}

6.无缓冲Channel

package main
import "fmt"
var mych1 = make(chan int,5) //无缓冲区
var mych2 = make(chan int,0) //无缓冲区
fuc mian(){
//无缓冲区,需要在子程中提前埋入读取,而后写入
    go func(){                  //1.使用匿名函数建立协程
        fmt.Println(<-mych2)    //2.读取,读取到打印,读取不到线程挂起
    }()
    mych2<-1                    //3.写入
//注意
    //写入后在同一个线程读取会报错
    //fmt.Println(<-mych2)
    //在主程中先写入,在子程中后读取也会报错
}

7.有缓冲管道和无缓冲管道

        有缓冲管道具备异步打的能力(写几个读一个或读几个)

        无缓冲管道具备同步的能力(写一个读一个)

8.单向管道和双向管道

        默认情况下所有的管道都是双向的

        单向管道应用于管道作为参数传递时,限制管道的写入和读取权限。

双向管道 var  mych  chan int = make(chan int,0)

只写管道var  mych chan<- int = make(chan<- int,0)

只读管道var  mych <-chan int = make(<-chan int,0)

双向管道可以转换为任意一种单向管道,单向管道不能转换为双向管道

package main
import "fmt"
func main(){
    //1.定义一个双向管道
    var mych chan int = make(chan int,5)
    //2.双向管道转单向
    var mych1 chan<- int
    mych1=mych
    var mych2 <-chan int
    mych2=mych
    //3.注意 管道之间赋值是地址传递,以上三个管道底层指向相同容器
}

9.单向管道作为函数参数

package main
import(
    "fmt"
    "math/rand"
    "time"
)

//定义生产者
func producer(mych chan<- int){
    rand.Seed(time.Now().UnixNano())
    for i:=0;i<10;i++{
        num:=rand.Intn(100)
        fmt.Println("生产者生产",num)
        //写入管道
        mych<-num
    }
    //生产完毕关闭管道
    close(mych)
    fmt.Println("生产者停止生产")
}
//定义消费者
func consumer(mych <-chan int){
    //不断从管道中获取数据,直到管道关闭
    for{
        if num,ok := <-mych;!ok{
            break
        }else{
            fmt.Println("消费了",num)
        }
    }
    fmt.Println("消费者停止消费")
}
func main(){
    var mych = make(chan int,5)
    go producer(mych)
    consumer(mych)
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。