8.4 Go select

8.4 Go select

Go语言引入了select关键字,用于处理异步IO问题,语义和switch特别相似。语法由select开始,每个条件由case语句来描述。每个case语句必须是IO操作

select {
    case <-chan1:
    //如果读取到channel的数据,就执行这里
    case chan2<-1:
    //如果成功向chan2写入数据,就执行这里
    default:
    //上述都失败了,进入这里
}

案例

使用select可以解决从管道取数据的阻塞问题

package main

import (
    "fmt"
    "time"
)

func main() {
    //定义一个管道
    intChan := make(chan int, 10)

    //循环写入数据
    for i := 0; i < 10; i++ {
        intChan <- i
    }
    //定义管道,可以写入string
    strChan := make(chan string, 5)
    for i := 0; i < 5; i++ {
        //格式化后写入string数据
        strChan <- "hello" + fmt.Sprintf("%d", i)
    }
    //传统的for循环遍历,必须close关闭channel,否则造成死锁
    //但是到底关闭哪个channel,并不那么容易选择
    //加上for无线循环,匹配所有的case,直到结束return
    for {
        select {
        //如果有数据被读取到,进入这个分支,并且intChan没关闭的话,也会自动匹配下一个case
        case v := <-intChan:
            fmt.Printf("从intChan读取到数据%d\n", v)
            time.Sleep(time.Second)
        case v2 := <-strChan:
            fmt.Printf("从strChan中读取到数据%s\n", v2)
            time.Sleep(time.Second)
        default:
            fmt.Printf("什么也没读到,再见\n")
            time.Sleep(time.Second)
            return
        }
    }

}

1.1.1. waitGroup等待组

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

func main() {
    /*
        同步等待组:WaitGourp,执行了wait的goroutine,要等待同步等待组中的其他的goroutine执行完毕。。
            内置的计数器:counter:0
            Add(),设置counter的值
            Done(),将counter减一,同Add(-1)

            以上两个方法可以设置counter的值,注意不能为负数,否则会引发恐慌。

            Wait(),哪个goroutine执行了,那么就会被阻塞,直到counter为0。解除阻塞
    */
    var wg sync.WaitGroup
    //fmt.Printf("%T\n",wg)
    //fmt.Println(wg)
    wg.Add(2)

    go printNum1(&wg)
    go printNum2(&wg)

    wg.Wait() //main,进入阻塞状态,底层计数器为0,接触阻塞。。
    //time.Sleep(1*time.Second)
    fmt.Println("main。。接触阻塞。。结束了。。。")
}

func printNum1(wg *sync.WaitGroup) {
    rand.Seed(time.Now().UnixNano())
    for i := 1; i <= 100; i++ {
        fmt.Println("子goroutine1,i:", i)
        time.Sleep(time.Duration(rand.Intn(1000))) //
    }
    wg.Done() //计数器减一
}

func printNum2(wg *sync.WaitGroup) {
    for j := 1; j <= 100; j++ {
        fmt.Println("\t子goroutine2,j:", j)
        time.Sleep(time.Duration(rand.Intn(1000)))
    }
    wg.Done()
}
上一篇:channel的关闭和广播机制测试


下一篇:WaitGroup