zoukankan      html  css  js  c++  java
  • Golang协程与通道整理

    协程goroutine
     
         不由OS调度,而是用户层自行释放CPU,从而在执行体之间切换。Go在底层进行协助实现
         涉及系统调用的地方由Go标准库协助释放CPU
         总之,不通过OS进行切换,自行切换,系统运行开支大大降低
     
     
    通道channel
     
    并发编程的关键在于执行体之间的通信,go通过通过channel进行通信
    channel可以认为类似其他OS体系中的消息队列,只不过在go中原生支持,因而易用
     
    消息队列有哪些值得关注的地方?常见问题包括创建、关闭或删除、阻塞、超时、优先级等,golang中也不例外。罗列如下:
         可否探测队列是满或空?或者说是否可以不阻塞地尝试读写?
         读阻塞和写阻塞时关闭会怎样?
         关闭后未读取的消息会被抛弃?
         往关闭的channel发送数据或读取数据会怎样?
         怎样探测channel的关闭?
         两个地方读或写阻塞同一个channel,有没有优先级?
         是否可以设定阻塞的超时时间?
         阻塞时怎样可以被弹出来?比如某些信号?
    事实上,知道存在这些问题并进行分门别类是重要的,但知道这些问题的答案却不紧要,因为一般不会太过古怪,使用时临时试验一下即可。
     
    已知的部分答案:
         好像不能不阻塞地尝试读写
         关闭会导致退出阻塞(似乎是一个不错的特性)
         可以探测关闭
         channel本身不能设定超时
    了解这些似乎已经足够。
     
     
    与众不同的地方值得我们重点留意,包括:
         除基本读写方式外,还有哪些特别的读写方式?在阻塞、关闭、超时方面又有什么不同?发现了select、range两个关键字
         推荐的多通道读
         推荐的同步方法
         推荐的超时方法
     
     
     
    select
     
    select可以实现无阻塞的多通道尝试读写,以及阻塞超时
         
    var c, c1, c2, c3 chan int
    var i1, i2 int
     
    select {
         case i1 = <-c1: //如果能走通任何case则随机走一个
            print( "received ", i1, " from c1 " )
         case c2 <- i2:
            print( "sent ", i2, " to c2 " )
         case i3, ok := (<-c3):
            if ok {
                    print( "received ", i3, " from c3 " )
            } else {
                    print( "c3 is closed ")
            }
         default: // 如果case都阻塞,则走default,如果无default,则阻塞在case
            // default中可以不读写任何通道,那么只要default提供不阻塞的出路,就相当于实现了对case的无阻塞尝试读写
            print( "no communication ")
    }
     
    实现阻塞超时的方法是,只要不给default出路,而在case中实现一个超时
     
    timeout := make (chan bool, 1)
    go func () {
        time.Sleep(1e9) // 这是等待1秒钟
        timeout <- true
    }()
     
    // 用timeout这个通道作为阻塞超时的出路
    select {
      case <-ch:
      // 处理从ch中读到的数据
      case <-timeout:
      // 如果case都阻塞了,那么1秒钟后会从这里找到出路
     
     
    range
     
    range可以在for循环中读取channel
    Go文档的翻译文是:对于信道,其迭代值产生为在该信道上发送的连续值,直到该信道被关闭。若该信道为 nil,则range表达式将永远阻塞
    经过试验,range会阻塞,并且可以通过关闭channel来解除阻塞。
     
    package main
     
    import (
           "fmt"
    )
     
    func main() {
          ch := makechan int )
     
           go func () {
                 for i := 0; i < 10; i++ {
                      ch <- i
                }
     
          }()
     
          
           for w := range ch {
                fmt.Println( "fmt print" , w)
                 if w > 5 {
                       //break // 在这里break循环也可以
                       close(ch)
                }
          }
          fmt.Println( "after range or close ch!" )
    }
     
     
    Golang的并发编程还有其他细节,但以上是最主要脉络。
  • 相关阅读:
    [PHP]socket的连接超时 与 读取/写入超时
    [PHP]引用返回与节省内存
    [PHP]实体类基类和序列化__sleep问题
    [PHP]日志处理error_log()函数和配置使用
    [PHP] 使用反射实现的控制反转
    [PHP] debug_backtrace()可以获取到代码的调用路径追踪
    [TCP/IP] TCP的传输连接管理
    [PHP] sys_get_temp_dir()和tempnam()函数报错与环境变量的配置问题
    [PHP] ubuntu下使用uuid扩展获取uuid
    [Linux] host dig nslookup查询域名的DNS解析
  • 原文地址:https://www.cnblogs.com/mafeng/p/7308753.html
Copyright © 2011-2022 走看看