go通道关闭
只有在当需要告诉接收者,我(发送者)不会再提供新的值的时候,才需要关闭通道。
只有发送者需要关闭通道,接收者永远不会需要。
问题1:如何关闭通道
通过执行close(ch)来关闭一个通道,这个操作会将通道标记为无法通过<- 接受更多的值。
给已经关闭的通道发送或者再次关闭都会导致运行时的 panic。在创建一个通道后使用 defer 语句是个不错的办法。
问题2:如何检测通道是不是关闭了(或阻塞了)
如果v收到值了,则ok的值是true。
根据ok的值,我们就能知道通道要么是关闭了,要么是阻塞了。
实现非阻塞通道的读取,需要使用 select。
使用 for-range 语句来读取通道是更好的办法,因为这会自动检测通道是否关闭:
for在循环遍历时,一旦结束,就退出。
记录运行时间和性能测试可以帮助你找到最小的缓存容量带来最好的性能。
通信开关:select语句
它的行为像是 “你准备好了吗” 的轮询机制;select
监听进入通道的数据。
在任何一个 case 中执行 break
或者 return
,select 就结束了。
注意:一个select语句只监听一次,监听到值后,就开始执行后面的语句。因此要用for来循环。
后台服务模式
每秒处理的频率可以根据机器负载(和 / 或)资源的情况而增加或减少。
滴答器:按一定频率滴答。
定时器:只发送一次。
简单超时模式
另一种超时:
有多个 case
符合条件时, select
对 case
的选择是伪随机的。
一个用到 recover
的程序停掉了服务器内部一个失败的协程而不影响其他协程的工作。
使用通道进行同步:使用一个通道接受需要处理的任务,一个通道接受处理完成的任务(及其结果)
对一个通道读数据和写数据的整个过程是原子性的。
使用锁的情景:
访问共享数据结构中的缓存信息
保存应用程序上下文和状态信息数据
使用通道的情景:
与异步操作的结果进行交互
分发任务
传递数据所有权
生成器
惰性求值
但是得小心,使用大量的 go 协程的开销可能会超过带来的性能增益。
通过巧妙地使用空接口、闭包和高阶函数,我们能实现一个通用的惰性生产器的工厂函数 BuildLazyEvaluator
(这个应该放在一个工具包中实现)。
需要抽象的能力,不然看这种代码会头疼,这种代码不如过程式代码一目了然,需要转大弯。
但这种代码能减小我们的代码文件,所以还是得硬着头皮看。
协程和通道在client-server类型的应用上大有用处
客户端请求本身包含了一个频道(channel),服务端可以用它来发送响应。