Go 语言圣经 8.4 Channels

8.4 Channels

知识点

  • 1.goroutine是Go语言程序的并发体的话,channels则是它们之间的通信机制
  • 2.一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息
  • 3.channel的零值也是nil
  • 4.两个相同类型的channel可以使用==运算符比较,同样可以和nil比较
  • 5.channel有发送和接受两个主要操作,都是通信行为
  • 6.<- channel在左侧是发送,在右侧是接收,不使用接收数据操作符也是合法的
  • 7.如果channel被关闭,则任何发送操作都会导致panic异常, 但是依然能接收到成功发送的数据,如果没有数据,则产生零值数据
  • 8.channel的make创建第二个参数,对应其容量
  • 9.无缓存Channels的发送和接收操作将导致两个goroutine做一次同步操作,因此被称为同步Channels
  • 10.happens before
  • 11.一个Channel的输出作为下一个Channel的输入, 这种串联的Channels就是所谓的管道(pipeline)
  • 12.串行的channel是无法知道另一个channel是否关闭的,
  • 但是关闭的channel会产生第二个值,为bool类型,ture代表接收到值,false表示channel已被关闭没有可接收的值
  • 13.带缓存的channel内部有一个元素队列,容量在创建时通过第二个参数指定
  • 14.带缓存channel会因为队列满导致发送等待,队列空接收等待
  • 15.发送的内容添加到队列尾部,接收内容是从队列头部取出并删除

代码

func test_Channels()  {

    //演示在netcat的channel_84
    //test_echo()

    //串行channel
    //test_pipeline()

    //使用单向channel实现串行
    //单向操作的channel中的只接受方是不需要关闭的,发送者关闭即可
    //任何双向channel向单向channel变量的赋值操作都将导致该隐式转换
    //naturals := make(chan int)
    //squares := make(chan int)
    //go counter_chan(naturals)
    //go squarer(squares, naturals)
    //printer(squares)

    //带缓存channel
    test_channel_cache()
}

func test_pipeline()  {
    naturals := make(chan int)
    squares := make(chan int)

    max := 100

    // Counter
    go func() {
        for x := 0; ; x++  {
            if x > max {
                close(naturals)
                break
            }
            naturals <- x
        }
    }()

    // Squarer
    go func() {
        for {
            x, ok := <- naturals
            if !ok {
                fmt.Println("naturals close")
                break
            }
            squares <- x * x
        }
        close(squares)
    }()

    // Printer (in main goroutine)
    for {
        x, ok := <-squares
        if !ok {
            fmt.Println("squares close")
            break
        }
        fmt.Println(x)
    }
}
func counter_chan(out chan<- int) {
    for x := 0; x < 100; x++ {
        out <- x
    }
    close(out)
}

func squarer(out chan<- int, in <-chan int) {
    for v := range in {
        out <- v * v
    }
    close(out)
}

func printer(in <-chan int) {
    for v := range in {
        fmt.Println(v)
    }
}
func test_channel_cache()  {
    chan_cache := make(chan string, 3)
    //channel缓存容量
    fmt.Println(cap(chan_cache))

    chan_cache <- "A"
    chan_cache <- "B"
    chan_cache <- "C"
    //有效元素个数
    fmt.Println(len(chan_cache))

    fmt.Println(<-chan_cache) // "A"
    //有效元素个数
    fmt.Println(len(chan_cache))

    chan_cache <- "AA"
    //有效元素个数
    fmt.Println(len(chan_cache))

    fmt.Println(<-chan_cache) // "B"
    fmt.Println(<-chan_cache) // "C"
    //有效元素个数
    fmt.Println(len(chan_cache))

    result := mirroredQuery()
    fmt.Println(result)
}
func mirroredQuery() string {
    responses := make(chan string, 3)
    go func() { responses <- request("asia.gopl.io") }()
    go func() { responses <- request("europe.gopl.io") }()
    go func() { responses <- request("americas.gopl.io") }()
    /*
        练习 8.11: 紧接着8.4.4中的mirroredQuery流程,
        实现一个并发请求url的fetch的变种。
        当第一个请求返回时,直接取消其它的请求。
        ----添加一个select,来终止goroutine
    */
    select {
    case <-done:
        return "终止成功"
    case <-responses:
        return <-responses
    }
}
func request(hostname string) (response string) {
    if hostname == "asia.gopl.io" {
        time.Sleep(1 * time.Second)
        return "111"
    }else if hostname == "europe.gopl.io" {
        time.Sleep(2 * time.Second)
        return "222"
    }else if hostname == "americas.gopl.io" {
        time.Sleep(500 * time.Millisecond)
        return "333"
    }
    return "000"
}
——不足之处,欢迎补充——

备注

《Go 语言圣经》

  • 学习记录所使用的GO版本是1.8
  • 学习记录所使用的编译器工具为GoLand
  • 学习记录所使用的系统环境为Mac os
  • 学习者有一定的C语言基础

代码仓库

猜你喜欢

转载自blog.csdn.net/liushihua147/article/details/80922655