6、Channel(通道)


簡單收發channel

func main()  {
    chanDemo()
}

func chanDemo() {
    c := make(chan int)
    go func() {
        for {
            n := <- c // 接收 channel 的數據
            fmt.Println(n)
        }
    }()

    // 發送 channel 數據
    c <- 1
    c <- 2

    time.Sleep(time.Millisecond)
}

 

channel 批量收發數據

func main()  {
    chanDemo()
}

func chanDemo() {
    // 定義 channel 數組
    var channels [10]chan int

    // 批量收數據
    for i := 0; i < 10; i++ {
        channels[i] = make(chan int)
        go worker(i,channels[i])
    }

    // 批量發數據
    for i := 0; i < 10; i++ {
        channels[i] <- i + 'a'
    }

    time.Sleep(time.Millisecond)
}

func worker (i int, c chan int){
    for {
        n := <- c // 接收 channel 的數據
        fmt.Printf("接收來自 %d 通道,數據%v\n",i,n)
    }
}

 

channel 通道類型

// 雙向通道
var a chan int

// 僅發送類型
var b chan<- int

//僅接收類型
var c <-chan int

 

channel 的緩沖區

func main()  {
    bufferedChan()
}

func bufferedChan() {
    c := make(chan int,3) // 給通道設定緩沖區
    go worker(0,c)
    c <- 11
    c <- 22
    c <- 33
    close(c) // 關閉通道

    time.Sleep(time.Millisecond)
}

func worker (i int, c chan int){
    // 若從通道收不到數據就退出
    //for {
    //    n,ok := <- c
    //    if !ok {
    //        break
    //    }
    //    fmt.Printf("接收來自 %d 通道,數據%v\n",i,n)
    //}

    // 同理,若通道有數據就打印
    for n := range c {
        fmt.Printf("接收來自 %d 通道,數據%v\n",i,n)
    }
}

 

channel 等待所有 goroutine 結束

func main()  {
    chanDemo()
}

type workStruct struct {
    in chan int
    done chan bool
}

func chanDemo() {
    // 定義 channel 數組
    var channels [10]workStruct
    for i := 0; i < 10; i++ {
        channels[i] = workStruct{
            in : make(chan int),
            done: make(chan bool),
        }
    }

    // 批量收數據
    for i,w := range channels{
        go worker(i,w)
    }

    // 批量發數據
    for i,w := range channels{
        w.in <- 'a' + i
    }

    // 當接收完 channels 里面的 done ,表示 channel 執行完畢
    for _,w := range channels{
        <-w.done
        close(w.in)
        close(w.done)
    }

    fmt.Printf("執行后續操作")
}

func worker (i int, c workStruct){
    // 同理,若通道有數據就打印
    for n := range c.in {
        fmt.Printf("接收來自 %d 通道,數據%v\n",i,n)
        c.done <- true
    }
}

 

WaitGroup 等待所有 goroutine 結束

func main()  {
    chanDemo()
}

type workStruct struct {
    in chan int
    wg *sync.WaitGroup
}

func chanDemo() {
    var wg sync.WaitGroup

    // 定義 channel 數組
    var channels [10]workStruct
    for i := 0; i < 10; i++ {
        channels[i] = workStruct{
            in : make(chan int),
            wg: &wg,
        }
    }

    wg.Add(10)

    // 批量收數據
    for i,w := range channels{
        go worker(i,w)
    }

    // 批量發數據
    for i,w := range channels{
        w.in <- 'a' + i
    }

    wg.Wait()

    fmt.Printf("執行后續操作")
}

func worker (i int, c workStruct){
    // 若通道有數據就打印
    for n := range c.in {
        fmt.Printf("接收來自 %d 通道,數據%v\n",i,n)
        c.wg.Done()
    }
}

 

select 接收或發送某個 channel 的值

func main() {
    var c1, c2 = generator(), generator()
    for {
        select {
        case n := <-c1:
            fmt.Println("c1里面來了數據", n)
        case n := <-c1:    
            fmt.Println("走這里", n) 
        case n := <-c2:
            fmt.Println("c2里面來了數據", n)
        }
    }
}

func generator() chan int {
    out := make(chan int)
    go func() {
        i := 0
        for {
            time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
            out <- i
            i++
        }
    }()
    return out
}

 

以下描述了 select 語句的語法:

    • 每個 case 都必須是一個通信
    • 所有 channel 表達式都會被求值
    • 所有被發送的表達式都會被求值
    • 如果任意某個通信可以進行,它就執行,其他被忽略。
    • 如果有多個 case 都可以運行,Select 會隨機公平地選出一個執行。其他不會執行。
      否則:
      1. 如果有 default 子句,則執行該語句。
      2. 如果沒有 default 子句,select 將阻塞,直到某個通信可以運行;Go 不會重新對 channel 或值進行求值。

 

傳統同步機制

WaitGroup

Cond

Mutex

type atomicInt struct {
    value int
    lock sync.Mutex
}

func (a *atomicInt) increment() {
    a.lock.Lock()
    defer a.lock.Unlock()
    a.value++
}

func (a *atomicInt) get() int {
    a.lock.Lock()
    defer a.lock.Unlock()
    return int(a.value)
}

func main() {
    var a atomicInt
    a.increment()
    go func() {
        a.increment()
    }()
    time.Sleep(time.Millisecond)
    fmt.Println(a.get())
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM