zoukankan      html  css  js  c++  java
  • go语言并发

    go语言并发

    goroutine

    goroutine格式

    • 为一个普通函数创建 goroutine 的写法如下:
    go funcName(参数列表)
    
    • 为一个匿名函数创建goroutine的写法如下
    go func(参数列表){
    函数体
    }(参数列表)
    

    goroutine创建流程

    1. Go 程序从 main 包的 main() 函数开始,在程序启动时,运行时(runtime)会默认为 main() 函数创建一个默认的 goroutine。

    2. 在 main() 函数的 goroutine 中执行到 go funcName语句时,归属于 funcName函数的 goroutine 被创建。

    3. 此时,main() 继续执行,funcName函数开始在自己的 goroutine 中执行,两个 goroutine 通过 Go 程序的调度机制同时运作。

    channel

    • 使用 go 关键字创建 goroutine 时,被调用函数的返回值会被忽略。

    • 如果需要在 goroutine 中返回数据,需要通过通道把数据从 goroutine 中作为返回值传出。

    • 在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。

    声明通道类型

    通道的元素类型就是在其内部传输的数据类型,声明如下:

    var 通道变量 chan 通道类型
    //通道类型:通道内的数据类型。
    //通道变量:保存通道的变量。
    

    chan 类型的空值是 nil,声明后需要配合 make 后才能使用。

    创建通道

    通道是引用类型,需要使用 make 进行创建,格式如下:

    通道实例 := make(chan 数据类型)
    //数据类型:通道内传输的元素类型。
    //通道实例:通过make创建的通道句柄。
    

    使用通道发送数据

    • 格式

    通道的发送使用特殊的操作符<-,将数据通过通道发送的格式为:

    通道变量 <- 值
    //通道变量:通过make创建好的通道实例。
    //值:可以是变量、常量、表达式或者函数返回值等。
    //值的类型必须与ch通道的元素类型一致。如果值是空接口类型,可以存放任意格式的数据
    
    • 发送将持续阻塞直到数据被接收

    把数据往通道中发送时,如果接收方一直都没有接收,那么发送操作将持续阻塞。

    使用通道接收数据

    通道接收同样使用 <- 操作符,通道接收有如下特性:

    1. 通道的收发操作在不同的两个 goroutine 间进行。

    由于通道的数据在没有接收方处理时,数据发送方会持续阻塞,因此通道的接收必定在另外一个 goroutine 中进行。

    1. 接收将持续阻塞直到发送方发送数据。

    如果接收方接收时,通道中没有发送方发送数据,接收方也会发生阻塞,直到发送方发送数据为止。

    1. 通道一次只能接收一个数据元素。

    2. 通道接收数据一共有下面4种写法

      1. 阻塞接收数据

        data := <-ch
        //执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。
        
      2. 非阻塞接收数据

        使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下:

        data, ok := <-ch
        //data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
        //ok:表示是否接收到数据
        

        非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要实现接收超时检测,可以配合 select 和计时器 channel 进行。

      3. 接收任意数据,忽略接收的数据

      阻塞接收数据后,忽略从通道返回的数据,格式如下:

      <-ch
      

      执行该语句时将会发生阻塞,直到接收到数据,但接收到的数据会被忽略。这个方式实际上只是通过通道在 goroutine 间阻塞收发实现并发同步。例如因为所有 goroutine 在 main() 函数结束时会一同结束,可以在main函数结束前等待其他函数的goroutine

      1. 循环接收

        通道的数据接收可以借用 for range 语句进行多个元素的接收操作,格式如下:

        for data := range ch {}
        

        通道 ch 是可以进行遍历的,遍历的结果就是接收到的数据。数据类型就是通道的数据类型。通过for遍历获得的变量只有一个,即上面例子中的 data。

    单向通道

    Go 的通道可以在声明时约束其操作方向,如只发送或是只接收。这种被约束方向的通道被称做单向通道。

    单向通道的声明

    只能发送的通道类型为 chan<-,格式如下:

    var 通道实例 chan<- 元素类型 
    

    只能接收的通道类型为 <-chan,格式如下:

    var 通道实例 <-chan 元素类型 
    

    创建单向通道

    通道实例 := make(<-chan 数据类型)
    通道实例 := make(chan<- 数据类型)
    

    带缓冲的通道Buffered Channels

    在无缓冲通道的基础上,为通道增加一个有限大小的存储空间形成带缓冲通道。

    带缓冲通道在发送时无需等待接收方接收即可完成发送过程,并且不会发生阻塞,只有当存储空间满时才会发生阻塞。

    同理,如果缓冲通道中有数据,接收时将不会发生阻塞,直到通道中没有数据可读时,通道将会再度阻塞。

    创建带缓冲的通道

    通道实例 := make(chan 通道类型, 缓冲大小)
    //缓冲大小:决定通道最多可以保存的元素数量。
    

    go语言通道的多路复用

    Go里面提供了一个关键字select监听channel上的数据流动。

    select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。

    在select里面还有default语法,select其实就是类似switch的功能,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)。

    select{
     case 操作1:
         响应操作1
     case 操作2:
         响应操作2
     …
     default:
         没有操作情况
    }
    

    go语言关闭通道后继续使用通道

    格式

    close(ch)
    

    被关闭的通道不会被置为 nil。如果对已经关闭的通道进行发送,将会触发panic。

    从已经关闭的通道接收数据或者正在接收数据时,将会接收到通道类型的零值,然后停止阻塞并返回。

    [参考资料http://c.biancheng.net/view/99.html]

  • 相关阅读:
    页面上传图片后立即预览
    MySQL用户管理
    两种方式实现java生成Excel
    总结个关于MySQL数据库的问题
    Properties操作指南
    Python笔记之不可不练
    Python笔记之不可不知
    SpringMVC一路总结(三)
    SpringMVC一路总结(二)
    SpringMVC一路总结(一)
  • 原文地址:https://www.cnblogs.com/jiangxiangxiang/p/10897259.html
Copyright © 2011-2022 走看看