go语言chan的关闭以及使用有无缓冲的结果

143 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 17 天,点击查看活动详情 

当chan传输完成的时候,要及时关闭chan,注意有发送方和接收方,即生产者和消费者。

在生产端关闭!消费端不要关闭chan。而是用 v,ok := <-ch 读取chan。对已关闭的chan。

  • 读:不断返回该chan类型的零值,int为0,string为"",结构体的零值为空结构体,布尔类型,零值是 false,指针的零值为nil、零值是nil的还有:error, map, chan, slice, interface{}
  • 写:panic
  • 再次关闭:panic
package groutine

import (
   "fmt"
   "testing"
   "time"
)

func service() string { // 快
   time.Sleep(time.Millisecond*50)
   return "Done"
}

func otherTask() { // 慢
   fmt.Println("working on something else")
   time.Sleep(time.Millisecond*100)
   fmt.Println("Task is Done.")
}

func AsyncService() chan string {
   retCh := make(chan string)
   go func() {
      ret := service() // Done
      fmt.Println("returned result.")
      retCh <- ret // 一直阻塞,直到Done传入这里面。
      // 这个channel的作用就是一直阻塞,直到service执行完。
      fmt.Println("service exited.")
      // 主进程一直在阻塞,所以这里是最后才执行
   }()
   return retCh
}

func TestChan(t *testing.T) {
   retCh := AsyncService() // 执行一个异步的操作。异步返回结果。
   otherTask()             // 而由于AsyncService()函数中,并没有阻塞所以先会执行其他任务。
   fmt.Println(<-retCh)    // 一直阻塞,直到从retCh中读出信息,即service()函数执行完毕。
}

虽然otherTask后执行,但是先输出,就是chan起到了阻塞的作用。

  • 无缓冲 result make(chan string) result
 working on something else
 returned result.
 Task is Done.
 Done
 service exited.

无缓冲,AsyncService阻塞,直到最后才service执行完之后才结束。比主进程后执行完成。

  • 有缓冲 result make(chan string,1) result
 working on something else
 returned result.
 service exited.
 Task is Done.
 Done

有缓冲的状态下,这个AsyncService不会阻塞。 这个异步任务也就马上结束并返回。 比主进程先执行完成。

image.png

此外chan可以作为多渠道的选择

   select {
   case ret := <- retCh1:
      t.Logf("result: %s",ret)
   case ret := <- retCh2:
      t.Logf("result: %s",ret)
   default:
      t.Error("Nothing Return")
   }

超时的控制

   select {
   case ret := <- retCh1:
      t.Logf("result: %s",ret)
   case <-time.After(time.Second*1):
      t.Error("Time Out")
   }

当这个函数超过这个时间,之后便会返回错误