二一:GO语言的goroutine(协程)和channel(管道),重点!!!

前言:要了解协程和管道首先得了解以下四个概念

  进程和线程简单说明

  1.进程就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位

  2.线程是进程的一个执行实例,是程序执行的最小单元,它是比进程更小的独立运行的基本单位

  3.一个进程可以创建销毁多个线程,同一个进程的多个线程可以并发执行

  4.一个程序至少有一个进程,一个进程至少有一个线程

个人理解:把计算机比作一家公司,程序就是这家公司的部门,进程就是公司安排的某个工作内容的完成过程,线程就是部门里处理这个工作内容的人去完成的实例,公司下发工作内容就相当于给部门下发任务,由公司(这里公司就是只CPU,后面会跟并发和并行有关联)来调动相应的人数去处理这个或者这些任务,如有错误请指出,谢谢。

  并发和并行

  1.多线程程序在单核上运行,就是并发

  2.多线程程序在多核上运行,就是并行

个人理解:沿用上一个例子,并发就是有多个任务安排,但是现在部门内部只有一个人,这个人就得同时处理所有工作内容,感觉上是所有的任务都在同时处理,但实际上在一个时间点上,这个人只能处理一个问题,只是在不停地切换不同的任务处理,而非处理完成一个任务后再切换到下一个任务。并行就是部门内部有多个人,可以同时处理多个任务

  

GO的协程和主线程

  1.GO主线程(有程序员直接称为线程/也可以理解成进程),一个GO线程上,可以起多个协程,可以这样理解,协程是轻量级的线程(编译器做优化)。

  2.GO协程的特点

  • 有独立的栈空间
  • 有共享程序堆空间
  • 调度由用户控制
  • 协程是轻量级的线程

goroutine 快速入门小结

  1.主线程是一个物理线程吗,直接作用在cpu上的,是重量级的,非常消耗cpu资源。

  2.协程从主线程开启的,是轻量级的线程,是逻辑态的。对资源消耗相对小。

  3.Golang的协程机制是重要的特点,可以轻松的开启上万个协程。其他编程语言的并发机制是一般基于线程的,开启过多的线程,资源消耗大,这就突显了Golang在并发上的优势

goroutine的调度模型(MPG模式)

  基本介绍

  M:操作系统的主线程(是物理线程)

  P:协程执行需要的上下文

  G:协程

简单来说,就是一个协程阻塞了,会把后续操作自动放到其余空闲的协程中执行,等到阻塞协程完成后,会把剩余的任务又使用该线程继续执行。这样来回切换可以保证阻塞的协程不会影响效率。达成并发/并行的效果

内容较多,需详细了解请自行搜索查询。

Channel(管道)

  在协程中进行相互通信时(都要使用同一个全局变量)会产生资源竞争(同时对某一个全局变量进行读写)的问题。

  channel用于解决不同的goroutine之间通信的问题,也可以使用加互斥锁的方式来达成这个目的。但互斥锁没这玩意儿好。

  基本介绍

    1.channel本质就是一个数据结构-队列

    2.数据是先进先出,与栈是相反的,栈是先进后出

    3.线程安全,多个goroutine访问时,不需要加锁,本身就是线程安全的

    4.channel是有类型的,一个string的channel只能存放string类型的数据

  定义/声明

    var 变量名 chan 数据类型

  举例:

    var intChan chan int

    var stringChan chan string

    var structChan chan Struct (结构体)

    var mapChan chan map[string]int (map)

  channel是一个引用类型,必须初始化才能写入数据,即使用make进行初始化,第二个参数为channel的长度

  int类型的管道只能存放int类型的数据

  

 

 

  给管道写入数据,拿上面的intChan举例

    

 

   读取管道中的数据

    

 

  channel的遍历

    channel支持for-range的方式进行遍历,但注意两个细节

      1.在遍历时,如果chanel没有关闭,则会出现deadlock的错误

      2.在遍历时,如果channel已经关闭,则会正常遍历数据,遍历完后,就会退出遍历

 

channel和goroutine使用的注意事项

    1.channel总只能存放指定的数据类型

    2.channel的数据放满后就不能再放入

    3.如果从channel取出数据后,可以继续放入

    4.在没有使用协程的情况下,如果channel的数据取完了,再取就会报dead lock,channel在取值时,实际上会返回两个值,x,ok:=<-chan,第二个值为ok,在成功取出,为false则失败

    5.使用内置函数close可以关闭channel,当channel关闭后,就不能再向channel写数据了,但是仍然可以从该channel读取数据。

    6.在默认情况下,channel管道是双向的,即可度又可写

      var chan2 chan <- int   //只可写入的int型管道

      var chan2 <-chan int    //只可读取的int型管道

    7.使用select可以解决从channel管道中读取数据的阻塞问题

    8.groutine中使用recover,解决协程中出现的panic,防止程序出现崩溃

 

  

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章