GO channel

理念

GO语言并发模型CSP: 提倡通过通信共享内存,而非通过共享内存实现通信

如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制

 

 

示例

关闭后任然可以读取

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    close(ch)
    a, ok1 := <-ch
    b, ok2 := <-ch
    c, ok3 := <-ch
    fmt.Println(a, ok1)
    fmt.Println(b, ok2)
    fmt.Println(c, ok3)
}

执行:

1 true
2 true
0 false

 

异常示例

# 无缓冲通道导致异常

import "fmt"

func baseTest() {
    ch := make(chan int)
    ch <- 10
    fmt.Println("发送成功")
}

func main() {
    baseTest()
}

执行:fatal error: all goroutines are asleep - deadlock!

原因:ch := make(chan int) 创建的是无缓冲通道,只有在有地接收值时才会发送成功。

# 通道无空间,继续读取

func testClose() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    //close(ch)
    a, ok1 := <-ch
    b, ok2 := <-ch
    c, ok3 := <-ch
    fmt.Println(a, ok1)
    fmt.Println(b, ok2)
    fmt.Println(c, ok3)
}

执行:fatal error: all goroutines are asleep - deadlock!

# 关闭后,任往通道发送

func main() {
    ch := make(chan int, 2)
    ch <- 1
    close(ch)
    ch <- 2
    a, ok1 := <-ch
    b, ok2 := <-ch
    c, ok3 := <-ch
    fmt.Println(a, ok1)
    fmt.Println(b, ok2)
    fmt.Println(c, ok3)
}

执行:

panic: send on closed channel

 

 

 

#解1:无缓冲通道

import "fmt"

func recv(ch chan int) {
    ret := <- ch
    fmt.Println("接收成功: ", ret)
}

func unBuffer() {
    ch := make(chan int)
    go recv(ch)
    ch <- 10
    fmt.Println("发送成功")
}

func main() {
    unBuffer()
}

执行:

接收成功: 10
发送成功

#解2:有缓冲通道

import "fmt"

func buffer() {
    ch := make(chan int, 2)
    ch <- 10
    fmt.Println("发送成功")
}
func main() {
    buffer()
}

执行:

发送成功

问题:当发送到chan大于其长度,并且没有消费时,造成死锁

import "fmt"

func buffer() {
    ch := make(chan int, 2)
    ch <- 10
    ch <- 11
    ch <- 12
    fmt.Println("发送成功")
}
func main() {
    buffer()
}

执行:

fatal error: all goroutines are asleep - deadlock! 

 

综合示例

读取对通道a中的数字,在通道b中平方

package main

import (
    "fmt"
    "sync"
)

var wg2 sync.WaitGroup

func f1(ch1 chan int) {
    defer wg2.Done()
    for i := 0; i < 100; i++ {
        ch1 <- i
    }
    close(ch1)
}

func f2(ch1, ch2 chan int) {
    defer wg2.Done()
    for {
        x, ok := <-ch1
        if !ok {
            break
        }
        ch2 <- x * x
    }
    close(ch2)
}

func testClose() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    close(ch)
    a, ok1 := <-ch
    b, ok2 := <-ch
    c, ok3 := <-ch
    fmt.Println(a, ok1)
    fmt.Println(b, ok2)
    fmt.Println(c, ok3)
}

func main() {
    //testClose()
    a := make(chan int, 100)
    b := make(chan int, 100)
    wg2.Add(2)
    go f1(a)
    go f2(a, b)
    wg2.Wait()
    for x := range b {
        fmt.Println(x)
    }
}

执行:

0
1
4
9
16

...

单向通道

<-chan:只做输出的通道

chan<-:只做输入的通道

示例: 重写上面例子中f2

func f2Uni(ch1 <-chan int, ch2 chan<- int) {
    defer wg2.Done()
    for {
        x, ok := <-ch1
        if !ok {
            break
        }
        ch2 <- x * x
    }
    close(ch2)
}

 

posted @ 2022-02-06 11:09  jihite  阅读(176)  评论(0编辑  收藏  举报