定义channel:make(chan 类型,容量)

  1. ch := make chan string):
  2. 写端: ch <- "hehe" 。写端写数据,读端不在读。写端阻塞
  3. 读端: str := <- ch 。读端读数据, 同时写端不在写,读端阻塞。

channel同步,数据传递:

  1. 写端: ch <- "hehe" 。写端写数据,读端不在读。阻塞
  2. 读端: str := <- ch 。读端读数据, 同时写端不在写,读端阻塞。
  3. len(ch) channel 中剩余未读取数据个数。 capch): 通道的容量。

无缓冲channel: —— 同步通信

  1. 创建: ch := make(chan int) make(chan int, 0)
  2. 通道容量为0 len = 0 不能存储数据。
  3. channel 应用于 两个go程中。 一个读,另一个写。
  4. 具备同步的能力。 读、写同步。(打电话)

有缓冲channel:—— 异步通信

  1. 创建: ch := make(chan int, 5)
  2. 通道容量为非0len(ch) channel 中剩余未读取数据个数。 capch): 通道的容量。
  3. channel 应用于 两个go程中。一个读,另一个写。
  4. 缓冲区可以进行数据存储。存储至 容量上限,阻塞。 具备 异步 能力,不需同时操作channel缓冲区(发短信)

关闭channel: 无、有缓冲

  1. 确定不再相对端发送、接收数据。关闭channel 使用 close(ch) 关闭channel
  2. 对端可以判断 channel 是否关闭:
  3. if num ok := <-ch ; ok == true {
  4. 如果对端已经关闭, ok --> false . num无数据。
  5. 如果对端没有关闭, ok --> true . num保存读到的数据。
  6. 可以使用 range 替代 ok
  7. for num := range ch { // ch 不能替换为 <-ch
  8. }
  9. 总结: 1. 数据不发送完,不应该关闭。
  10. 2. 已经关闭的channel 不能再向其写数据。 报错:panic: send on closed channel
  11. 3. 写端已经关闭channel 可以从中读取数据。
  12. 读无缓冲channel 读到0 —— 说明:写端关闭。
  13. 读有缓冲channel 如果缓冲区内有数据,先读数据。读完数据后,可以继续读。 读到 0

单向channel:

  1. 默认的channel 是双向的。 var ch chan int ch = make(chan int)
  2. 单向写channel: var sendCh chan <- int sendCh = make(chan <- int) 不能读操作
  3. 单向读channel: var recvCh <- chan int recvCh = make(<-chan int)
  4. 转换:
  5. 1. 双向channel 可以 隐式转换为 任意一种单向channel
  6. sendCh = ch
  7. 2. 单向 channel 不能转换为 双向 channel
  8. ch = sendCh/recvCh error!!!
  9. 传参: 传【引用】

生产者消费者模型:

  1. 生产者: 发送数据端
  2. 消费者: 接收数据端
  3. 缓冲区: 1. 解耦 降低生产者 消费者之间 耦合度
  4. 2. 并发 (生产者消费者数量不对等时,能保持正常通信)
  5. 3. 缓存 (生产者和消费者 数据处理速度不一致时, 暂存数据)
  6. 模型代码实现。---- 模拟订单代码实现。 参阅讲义

定时器:

  • Timer:创建定时器,指定定时时长,定时到达后。 系统会自动向定时器的成员 C 写 系统当前时间。 (对 chan 的写操作)
    1. type Timer struct {
    2. C <-chan Time
    3. r runtimeTimer
    4. }
    5. sleep()
    6. NewTimer
    7. After

读取 Timer.C 得到 定时后的系统时间。并且完成一次 chan 的 读操作。

  • time.After() 定时:

    指定定时时长,定时到达后。 系统会自动向定时器的成员 写入 系统当前时间。

    返回 可读 chan 。 读取,可获得系统写入时间。

  • 总结: Sleep、NewTimer、After —— time包

定时器的 停止、重置:

  1. 1 创建定时器 myTimer := time.NewTimer(2 * time.Second)<br /> <br /> 2) 停止: myTimer.Stop —— 将定时器归零。 <-myTimer.C 会阻塞
  2. 3 重置:myTimer.Reset(time.Second)

周期定时:

  1. type Ticker struct {
  2. C <-chan Time
  3. r runtimeTimer
  4. }
  5. 1 创建周期定时器 myTicker := time.NewTicker(time.Second)
  6. 定时时长到达后,系统会自动向 Ticker C 中写入 系统当前时间。
  7. 并且,每隔一个定时时长后,循环写入 系统当前时间。
  8. 2 go 程中循环读取 C。获取系统写入的时间。
  • select:
    作用: 用来监听 channel 上的数据流动方向。 读?写?
  1. 用法: 参考 switch case 语句。 但!case后面必须是IO操作,不可以任意写判别表达式。
  2. 注意事项:
  3. 1. 监听的case中,没有满足监听条件,阻塞。
  4. 2. 监听的case中,有多个满足监听条件,任选一个执行。
  5. 3. 可以使用default来处理所有case都不满足监听条件的状况。 通常不用(会产生忙轮询)
  6. 4. select 自身不带有循环机制,需借助外层 for 来循环监听
  7. 5. break 跳出 select中的一个case选项 。类似于switch中的用法。
  • select实现fibonacci数列:
  1. 1 1 2 3 5 8 13 21 34 55 89
  2. x = y
  3. y = x+y

select 超时处理:

  1. select 监听 time.After() channel 的读事件。 如果定时时间到,系统会向该channel中写入系统当前时间。
  2. select {
  3. case <-time.After(time.Second * 5)
  4. 定时到达后,要处理的内容
  5. }