GoLang并发编程(第三阶段)| 青训营笔记

82 阅读2分钟

只读与只写管道

只读: <-chan [type]

只写:chan<- [type]

// 只读
func onlyRead(readChan <-chan int) {
    for {
       if v, ok := <-readChan; ok {
          fmt.Println("值:", v)
       }
    }
    //readChan <- 123 // Invalid operation: readChan<- 123 (send to the receive-only type <-chan int)
}

// 只写
func onlyWrite(writeChan chan<- int) {
    for i := 0; i < 6; i++ {
       writeChan <- i
    }
    //<-writeChan // Invalid operation: <-writeChan (receive from the send-only type chan<- int)
    close(writeChan)
}

close关闭管道的优化手段

在前面的案例中,我们可以发现我们在创建管道之后,我们先是往里面添加数据,然后再取数据,同时在将数据加入完毕之后,就要将管道关闭,不允许再添加数据,但是有的时候,我们不能准确的把握什么时候去关闭这个管道,就像我们之前在处理主线程和协程执行时间不一致时使用sleep来阻塞主线程。在案例中,我们可以发现我们在处理exitChan管道时,其实没有去特意关闭它,而是通过固定的遍历次数来结束遍历。主要是因为这里不清楚什么时候去关闭管道。

使用select

select语句 就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应的case动作。有了 select语句,可以实现 main主线程 与 goroutine线程 之间的互动。

select {
    case <-ch1 :     // 检测有没有数据可读
        // 一旦成功读取到数据,则进行该case处理语句
    case ch2 <- 1 :  // 检测有没有数据可写
        // 一旦成功向ch2写入数据,则进行该case处理语句
    default:
        // 如果以上都没有符合条件,那么进入default处理流程
}

使用select实现管道遍历

在之前的案例中,我们可以再遍历exitChan时,使用select去遍历;当遍历的时候不再匹配任何一个case时,此时就应该进入default,执行相关的退出遍历的操作,那么这里的退出遍历,我们可以采用什么方式呢?大家可以先思考一下:

EXIT:
    for {
       select {
       
       case  v := <-exitChan :
           fmt.Println("遍历一次exitChan", v)
       default :
           break EXIT
           // goto EXIT2
       }
    }
    // EXIT2

参考:golang跳出for select 循环,需要break配合标签才行

参考:go中select语句

最后

最近学习的时间比较有限,整理的笔记会相对少一些,感觉有点想一点了解一个go的小知识。最近写的都会比较少,主要是专业课考试,所以要花些时间来复习功课。