Golang通道的无阻塞读写的方法示例

  

无论是无缓冲通道,还是有缓冲通道,都存在阻塞的情况,但其实有些情况,我们并不想读数据或者写数据阻塞在那里,有1个唯一的解决办法,那就是使用选择结构。

这篇文章会介绍,哪些情况会存在阻塞,以及如何使用选择解决阻塞。


阻塞场景共4个,有缓存和无缓冲各2个。

无缓冲通道的特点是,发送的数据需要被读取后,发送才会完成,它阻塞场景:

<李>

通道中无数据,但执行读通道。

<李>

通道中无数据,向通道写数据,但无协程读取。

//,场景1   func  ReadNoDataFromNoBufCh (), {   noBufCh :=, (chan  int)      & lt; -noBufCh   fmt.Println(得到no 获“read  buffer  channel  success")//,输出:   错误://,fatal  all  goroutines 断开连接;asleep 作用;僵局!   }//,场景2   func  WriteNoBufCh (), {   ch :=, (chan  int)      ch  & lt;作用;1   fmt.Println (“write  success  no  block")//,输出:   错误://,fatal  all  goroutines 断开连接;asleep 作用;僵局!   }

注:示例代码中输出的注释代表函数的执行结果,每一个函数都由于阻塞在通道操作而无法继续向下执行,最后报了死锁错误。

有缓存通道的特点是,有缓存时可以向通道中写入数据后直接返回,缓存中有数据时可以从通道中读到数据直接返回,这时有缓存通道是不会阻塞的,它阻塞的场景是:

<李>

通道的缓存无数据,但执行读通道。

<李>

通道的缓存已经占满,向通道写数据,但无协程读。

//,场景1   func  ReadNoDataFromBufCh (), {   bufCh :=, (chan , int, 1)      & lt; -bufCh   fmt.Println(得到no 获“read  buffer  channel  success")//,输出:   错误://,fatal  all  goroutines 断开连接;asleep 作用;僵局!   }//,场景2   func  WriteBufChButFull (), {   ch :=, (chan , int, 1)//,make  ch 满   ch  & lt;作用;100年      ch  & lt;作用;1   fmt.Println (“write  success  no  block")//,输出:   错误://,fatal  all  goroutines 断开连接;asleep 作用;僵局!   }


选择是执行选择操作的一个结构,它里面有一组案例语句,它会执行其中无阻塞的那一个,如果都阻塞了,那就等待其中一个不阻塞,进而继续执行,它有一个默认语句,该语句是永远不会阻塞的,我们可以借助它实现无阻塞的操作。

下面示例代码是使用选择修改后的无缓冲通道和有缓冲通道的读写,以下函数可以直接通过主要函数调用,其中的输出的注释是运行结果,从结果能看的出,在通道不可读或者不可写的时候,不再阻塞等待,而是直接返回。

//,无缓冲通道读   func  ReadNoDataFromNoBufChWithSelect (), {   bufCh :=, (chan  int)      if  v, err :=, ReadWithSelect (bufCh);, err  !=, nil  {   fmt.Println (err)   },{else    fmt.Printf(“读:% d \ n",, v)   }//,输出://,channel  has  no 数据   }//,有缓冲通道读   func  ReadNoDataFromBufChWithSelect (), {   bufCh :=, (chan , int, 1)      if  v, err :=, ReadWithSelect (bufCh);, err  !=, nil  {   fmt.Println (err)   },{else    fmt.Printf(“读:% d \ n",, v)   }//,输出://,channel  has  no 数据   }//,选择结构实现通道读   func  ReadWithSelect (ch  chan  int), (x , int, err 错误),{   select  {   case  x =, & lt; ch:   return  x, nil   默认值:   return  0, errors.New (“channel  has  no  data")   }   }//,无缓冲通道写   func  WriteNoBufChWithSelect (), {   ch :=, (chan  int)   if  err :=, WriteChWithSelect (ch);, err  !=, nil  {   fmt.Println (err)   },{else    fmt.Println (“write  success")   }//,输出://,channel 阻塞,还要not 写的   }//,有缓冲通道写   func  WriteBufChButFullWithSelect (), {   ch :=, (chan , int, 1)//,make  ch 满   ch  & lt;作用;100年   if  err :=, WriteChWithSelect (ch);, err  !=, nil  {   fmt.Println (err)   },{else    fmt.Println (“write  success")   }//,输出://,channel 阻塞,还要not 写的   }//,选择结构实现通道写   func  WriteChWithSelect (ch  chan  int), error  {   select  {   case  ch  & lt;安康;1:   return 零   默认值:   return  errors.New (“channel 封锁,,还要not  write")   }   }

Golang通道的无阻塞读写的方法示例