Go

Go-channel

shilinkun
2022-05-26 / 0 评论 / 288 阅读 / 正在检测是否收录...
博客网址:www.shicoder.top
微信:kj11011029
欢迎加群聊天 :452380935

这个系列主要是对go的一些语法和应用进行代码讲解

channel遍历

func main() {
    channels := make([]chan int, 10) 
    for i := 0; i < 10; i++ {
         go func(ch chan int) {
          time.Sleep(time.Second)
          ch <- 1 
         }(channels[i])
    }

    for ch := range channels { 
    fmt.Println("Routine ", ch, " quit!")
    }
    fmt.Println("结束")
}
func main() {
    ch := make(chan int, 10)
    for i := 0; i < 10; i++ {
        go func() {
            ch <- i
        }()
    }

    for range ch {
        <-ch
    }
    fmt.Println(1111)
}

上面两个代码的却别:

  • 第一个会正常输出
  • 第二个会阻塞

因为for range channel会一直读取channel,若没有close channel,还会继续遍历,则会出现死锁,而第一个中因为是for range channels,此时的channels是一个切片,遍历次数知道,所以不会出现死锁。

因此注意range channel时候,一定要close channel

非阻塞channel

func main() {
    var c1 chan string = make(chan string)
    func() {
        time.Sleep(time.Second)
        c1 <- "1"
    }()
    fmt.Println("c1 is", <-c1)
}

因为是无缓冲管道,有一个特点必须读写同时操作才会有效果,如果只进行读或者只进行写那么会被阻塞,因此我们只能使用go协程来杜绝阻塞

func main() {
    var c1 chan string = make(chan string)
    go func() {
        time.Sleep(time.Second)
        c1 <- "1"
    }()
    fmt.Println("c1 is", <-c1)
}

或者使用有缓冲管道

func main() {
    var c1 chan string = make(chan string, 1)
    func() {
        time.Sleep(time.Second)
        c1 <- "1"
    }()
    fmt.Println("c1 is", <-c1)
}

或者使用selectdefault来进行默认处理

func main() {
    var c1 chan string = make(chan string)
    var c2 chan string = make(chan string)
    time.Sleep(time.Second)
    select {
    case c := <-c1:
        fmt.Println(c)
    case c := <-c2:
        fmt.Println(c)
    default:
        fmt.Println("After one second!")
    }
}

// 或者使用time超时
func main() {
    var c1 chan string = make(chan string)

    select {
    case c := <-c1:
        fmt.Println(c)

    case <-time.After(time.Second):
        fmt.Println("After one second!")
    }
}
0

评论 (0)

取消