• 3.8 Go之通道(chan)


    3.8 Go之通道(chan)

    什么是通道?

    goroutine的通信管道

    如何李姐通道

    • 首先不要混淆goroutinechannel之间的关系

    • goroutine是并发的结构体

    • channel是每个结构体通信的桥梁

    channel的特点:

    channel是一个通信机制,每个channel都有一个特殊的类型,一个可以发送int类型的channel一般写为chan int go的并发特点:

    使用通道代替共享内存

    goroutinechannel关系:

    多个goroutine争抢数据会造成执行的低效率,使用队列的方式是最高效的。channel是队列一样的结构

    Go通道种类

    • 单向通道

    • 无缓冲通道

    • 带缓冲通道


    通道的特性

    特点:

    • 任何时候同时只能有一个goroutine访问通道进行发送和获取数据

    • 遵循先入先出的规则(First In First Out)

    声明通道类型(通道是一种类型)

    通道的声明方式:

    var 通道变量 chan 通道类型;
    • 通道类型:通道内的数据类型。

    • 通道变量:保存通道的变量。

    chan类型的空值是nil,声明后需要make才能使用

    创建通道

    通道的特点:

    通道是引用类型,要使用make进行创建。

    声明通道实例的方式:

    通道实例 := make(chan 数据类型)
    • 数据类型:通道内传输的元素类型。

    • 通道实例:通过make创建的通道句柄。

    实例:

    ch1 := make(chan int) // 存放int类型数据的通道
    ch2 := make(chan interface{}) // 创建一个空接口类型的通道, 可以存放任意格式

    type Equip struct{/* 一些字段 */}
    ch2 := make(chan *Equip) // 创建Equip指针类型的通道, 可以存放*Equip

    使用通道发送数据

    • 通道发送数据的格式

    • 通过通道发送数据的例子

    • 发送将持续阻塞直到数据被接收


    通道发送数据的格式

    使用特殊操作符<-,格式为:

    通道变量 <- 

    箭头指向make创建好的通道实例,将值传入通道实例当中

    • 通道变量:通过make创建好的通道实例。

    • 值:可以是变量、常量、表达式或者函数返回值等。值的类型必须与ch通道的元素类型一致。

    通道发送数据的例子

    make创建通道实例,<-向通道发送数据:

    // 创建一个空接口通道
    ch := make(chan interface{})
    // 将int类型数据放入通道中
    ch <- 0
    // 将string类型的数据放入通道中
    ch <- "Hello,World!"
    通道内的数据如果没有被接收将持续阻塞

    把数据往通道中发送时,如果接收方一直都没有接收,那么发送操作将持续阻塞。

    package main

    func main() {
       // 创建一个通道
       ch := make(chan int)

       // 将一个值放入通道
       ch <- 0
    }
    /*
    结果将持续阻塞,执行后会报错:
    fatal error: all goroutines are asleep - deadlock!
    */

    使用通道接收数据

    • 阻塞接收数据

    • 非阻塞接收数据

    • 接收任意数据,忽略接收的数据

    • 循环接收


    通道接收数据的特点:

    1. 使用操作符<-

    2. 通道的手法操作在两个goroutine中进行,若通道没有接收方则会持续阻塞。

    3. 接收持续阻塞直到发送方发送数据。

    4. 每次接收一个元素。

    阻塞接收数据

    <始终指向接收方

    data := <-ch
    /*
    执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。
    */
    非阻塞接收数据

    格式:

    data, ok := <-ch
    • data:表示接收到的数据。未接收到数据时,data为通道类型的零值。

    • ok:表示是否接收到数据。

    接收任意数据,忽略接收的数据

    阻塞接收数据,忽略从通道返回的数据:

    <-ch
    /*
    特点:
    1、执行语句会发生阻塞,直到接收到数据
    2、接收到的数据会被忽略
    */

    作用:

    通过通道在goroutine间阻塞收发实现并发同步

    示例:

    package main

    import "fmt"

    func main() {
       // 构建一个通道--->int类型的
       ch := make(chan int)

       // 开启一个匿名函数--->实现往通道中写入数据的功能
       go func() {
           // 开启goroutine
           fmt.Println("开启goroutine:")

           // 向通道当中写入数据
           ch <- 0

           // 关闭goroutine
           fmt.Println("关闭goroutine!")
      }()

       // 开始匿名等待
       fmt.Println("等待goroutine!")

       // 匿名等待
       <-ch
       /*
       开启 goroutine 后,马上通过通道等待匿名 goroutine 结束。
       */

       // 结束
       fmt.Println("结束!")
    }

    分析:

    <-ch会忽略接收的内容。所以不会报死锁的错误。

    循环接收

    借用for range语句进行多个元素接收:

    for data := range ch {
       
    }
    /*
    通道可遍历
    */

    示例代码:

    package main

    import (
       "fmt"
       "time"
    )

    /*
    遍历通道内容:
    1、创建一个通道
    2、循环往通道当中添加数据
    3、使用for range循环读取通道当中的数据以及类型
    */
    func main() {
       // 构建一个通道
       ch2 := make(chan int)

       // 创建一个匿名goroutine循环向通道当中添加数据
       go func() {
           // 循环添加0->3
           for i := 3; i >= 0 ; i-- {
               // 向通道当中发送数据
               ch2 <- i

               // 发送一次等待一秒
               time.Sleep(time.Second)
          }
      }()

       // 通过循环遍历读取通道内的数据--->遍历不是接收,不会造成死锁
       for data := range ch2 {
           fmt.Println(data)

           // 读到0跳出循环
           if 0 == data {
               break
          }
      }
    }
    /*
    当接收到数值 0 时,停止接收。如果继续发送,由于接收 goroutine 已经退出,没有 goroutine 发送到通道,因此运行时将会触发宕机报错。
    */s
  • 相关阅读:
    As3 模拟As2.0LoadVars 传参
    OracleERP库存管理
    OracleERP采购管理
    Oracle EBS R12文件系统结构
    OracleERP物料
    ORACLE APPLICATION 数据结构
    WIN7 X64 Setup Oracle Developer Suite 10g
    实例14. 库存补充操作——再订购点计划(Reorder Point Planning)
    OracleERP供应商
    ORACLE EBS环境下可以使用的开发语言和工具
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/16033285.html
Copyright © 2020-2023  润新知