Go 语言 协程和管道讲解


本文摘自网络,作者,侵删。

参考链接: 角度6-管道

Go 语言 协程和管道讲解 

一、进程和线程基本说明: 

进程是程序在操作系统中一次执行过程,是系统进行资源分配和调度的基本单位;线程是进程的一个执行实例,是程序最小单元,它是比进程更小的能独立运行的基本单位;一个进程可创建和销毁多个线程,同一个进程的多个线程可以并发执行;一个程序至少有一个进程,一个进程至少有一个线程; 

 

 举个栗子: 

 使用的迅雷客户端,打开迅雷就是开启了一个进程,而下载多个视频,就是多个线程在工作; 

 

二、并发、并行简单说明: 

1.并发: 

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

特点: 

  多个任务作用在一个cpu上;从微观的角度看,在一个时间点上,其实只有一个任务在执行,只是时间切片较块;  

2.并行: 

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

特点: 

  多个任务作用在多个cpu上;从微观的角度看,在一个时间点上,多个任务在同时执行;  

并行的速度要快 

三、协程基本介绍: 

1.基本概念: 

一个线程上,可以有多个协程,协程是轻量级的线程; 

协程特点: 

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

2.快速案例: 

package main


import (

    "fmt"

    "strconv"

    "time"

)


func test(){

    for i:= 0; i < 10; i++{

        fmt.Println("test() " +  strconv.Itoa(i))

        time.Sleep(time.Second)

    }

}


func main() {

    go test()  // 开启一个协程

    for i := 0; i < 10; i++{

        fmt.Println("main()" + strconv.Itoa(i))

        time.Sleep(time.Second)

    }

}

 

主线程是一个物理线程,直接作用在CPU上,非常消耗CPU资源;协程从主线程开启的,是轻量级的线程,对资源消耗小;其它语言的并发机制一般是基于线程,开启过多的线程,资源消耗较大,这就体现出golang的优势; 

3.MPG模式基本介绍: 

M:操作系统的主线程(物理线程);P:协程执行需要的上下文;G:协程; 

MPG模式介绍 

4.设置cpu数: 

package main


import (

    "fmt"

    "runtime"

)


func main () {

    // 查看系统cpu个数

    cpuNum := runtime.NumCPU()

    // 可以自己设置使用多个cpu

    runtime.GOMAXPROCS(cpuNum)

    fmt.Println("cpuNum", cpuNum)

}

 

go 1.8版本以后,默认让程序运行在多核上,可不用设置;go 1.8版本前,需要设置,才可以更高效的利用cpu; 

四、协程之间如何通讯? 

1.全局变量加锁: 

package main


import (

    "fmt"

    "sync"

    "time"

)


var (

    myMap = make(map[int]int, 10)

    // 声明一个全局互斥锁

    // lock 是一个全局互斥锁 sync 是包 同步的意思 Mutex:是互斥

    lock sync.Mutex

)

// test函数计算 n的阶乘, 将结果放到map中

func testCount(n int) {

    res := 1

    for i := 1; i <= n; i++ {

        res *=i

    }

    // 加锁

    lock.Lock()

    myMap[n] = res

    // 解锁

    lock.Unlock()

}

func main () {

    // 开启多个协程完成20个任务

    for i := 1; i <= 20; i++{

        go testCount(i)

    }

    time.Sleep(time.Second * 5)

    lock.Lock()

    for k, v := range myMap{

        fmt.Printf("map[%d]=%d\n", k, v)

    }

    lock.Unlock()

}

 

 

 声明全局互斥锁;写的时候加索,写完释放锁;读的时候加索,读完释放锁; 

 否则会出现资源竞争的问题;报错信息:fatal error: concurrent map writes 

 

全局变量加锁同步是低级程序操作: 

主线程等待所有协程全部完成时间很难确定,因为主线程结束,不管协程是否执行完,程序就此结束;通过全局变量加锁同步实现通讯,也不利于多个协程对全局变量的读写操作; 

2.使用管道channel解决: 

2.1.channel的介绍: 

 声明方式: 

   

   var 变量名 chan 数据类型 

    channel 本质 就是一个数据结构(队列);  数据是先进先出(FIFO);  线程安全,多个协程访问,不需要加锁;  channel只能存放指定数据类型; 

   

   如:一个string的channel只能存放string类型数据 

    channel是引用类型; 

   

   必须初始化才能写入数据,即make后才能使用 

    channel数据放满后,就不能在放;  channel数据取完后,再取就会报错;  

2.2.快速栗子: 

package main


import "fmt"


func main() {

    // 管道的使用

    // 1.创建一个可以存放3个int类型的管道

    var intChan chan int

    intChan = make(chan int, 3)

    // 2.查看intChan 是什么?

    fmt.Printf("intchan:%v\n", intChan)  // 输出结果: intchan:0xc00008c080 可以看出是引用类型

    // 3.向管道写入数据

    intChan<- 10

    num := 100

    intChan<- num  // 也可以写入常量

    // 4.看看管道的长度和cap(容量:定义的长度跟容量是相等的, 不同于map类型等)

    fmt.Printf("channel len=%v cap=%v\n", len(intChan), cap(intChan))

    //  4输出结果:channel len=2 cap=3


    //5.从管道中读取数据

    //var num2 int

    num2 := <-intChan

    fmt.Println("取出的num2=", num2)

    fmt.Printf("channel len=%v cap=%v\n", len(intChan), cap(intChan))

    // 5输出结果:channel len=1 cap=3

}

 

 

 注意: 

 如果往管道中存入数据,管道已经满了,或者取数据,管道中已经没有值,会报错信息fatal error: all goroutines are asleep - deadlock! 

 

2.3.channel关闭: 

使用内置函数close可以关闭channel,当channel关闭后,就不能向channel写数据,但是仍然可以读数据; 

举个栗子: 

package main


import "fmt"


func main() {

    // 创建一个管道,大小为3

    intChan := make(chan int, 3)

    intChan <- 3

    intChan <- 5

    // 将管道进行关闭

    close(intChan)

    // 此时会无法写入, 因为管道已经关闭: 报错信息 panic: send on closed channel

    //intChan <-6

    n1 := <- intChan

    fmt.Println("可以从管道中读取值:", n1)

}

 

2.4.channel遍历: 

channel 支持 for-range的方式进行遍历: 

阅读剩余部分

相关阅读 >>

java和Golang对比

聊聊dubbo-Go-proxy的apifilter

Golang的多态

游戏服务器框架Gonet

深入理解Go的interface

Go学习笔记(一):Go语言开发环境搭建

未编译的python代码比Go慢100倍,编译后呢?

Golang到底能做什么

Go语言闭包谈函数式编程

Go封装、继承、多态

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...