Go语言Goroutinue和管道效率详解

2022-09-25 17:10:29
目录
goroutinue基本介绍进程和线程说明并发和并行同步和异步Go协程和Go主线程go协程特点goroutinue基本使用实验代码效果图执行流程图goroutinue的调度模型MPGMPG运行状态1MPG运行状态2管道(channel)不同协程之间如何通讯全局变量加锁同步缺陷管道基本介绍管道基本使用 声明和定义管道关闭和遍历关闭遍历管道注意事项综合案例

goroutinue基本介绍

进程和线程说明

    进程介绍程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位线程只是进程的一个执行实例或流程,是程序执行的最小单元一个进程可以有多个线程,但是一个线程只能对应一个进程同一个进程中的多个线程可以并发执行程序:运行起来的应用程序就称为进程,也就是当程序不运行的时候我们称为程序,当程序运行起来他就是一个进程,通俗的理解就是不运行的时候是程序,运行起来就是进程。程序只有一个,但是进程有多个

    并发和并行

      并发:多个任务依次执行,执行过程中多个任务可以替换执行,在某一个时刻是一个任务在执行,但是在某个时间段内是多个任务在执行。并行:多个任务没有顺序,同时执行,最终的执行结果跟耗时最长的任务有关串行:多个任务依次执行,上一个任务没有完成时不能执行后续的任务,最明显的同步执行过程

      同步和异步

        同步:描述的就是串行执行过程,多个任务按照顺序依次执行的过程异步:描述的就是并发和并行的过程,就是多个任务在一个时间段内同时执行,每个任务都不会等待其他任务执行完成后执行

        Go协程和Go主线程

        Go主线程:一个Go线程上,可以起多个协程,协程是轻量级的线程

        go协程特点

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

          goroutinue基本使用

          实验代码

          package main
          import (
          	"fmt"
          	"runtime"
          	"strconv"
          	"time"
          )
          func main() {
          	//编写一个函数,每隔1s输出"hello,world"
          	//要求主线程和gorutine同时执行
          	go test()
          	//在主线程中,开启一个goroutine,该协程每隔1s输出"hello,world"
          	for i:=1;i<=10 ; i++ {
          		fmt.Println("main() hello world", strconv.Itoa(i))
          		time.Sleep(time.Second)
          	}
          	//查询Golang运行的cpu数
          	fmt.Println(runtime.NumCPU()) //4
          	//设置Golang运行的cpu数
          	//runtime.GOMAXPROCS(runtime.NumCPU()-1)	//3
          }
          func test(){
          	for i:=1;i<=10 ; i++ {
          		fmt.Println("test() hello world",strconv.Itoa(i))
          		time.Sleep(time.Second)
          	}
          }
          

          效果图

          执行流程图

          goroutinue的调度模型

          MPG

          MPG运行状态1

          MPG运行状态2

          管道(channel)

          不同协程之间如何通讯

            全局变量加锁同步channel

            使用全局变量加锁同步改进程序

              因为没有对全局变量加锁,因此会出现资源夺取问题,代码会出现错误,提示concurrent>加入互斥锁

              全局变量加锁同步缺陷

                主线程在等待所有goroutine全部完成的时间很难确定如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有goroutine处于工作状态,这时也会随着主线程的结束而结束不利于多个协程对全局变量的读写操作

                管道基本介绍

                  管道本质介绍一个数据结构-队列数据是先进先出线程安全,无需加锁管道有类型

                  管道基本使用>

                  管道关闭和遍历

                  关闭

                  使用内置函数close可以关闭channel,关闭后,就不能写入数据,但可读

                  遍历

                    在使用for--range遍历时,如果channel没有关闭,则回出现deadlock错误在使用for--range遍历时,如果channel已经关闭,则会正常遍历数据

                    代码

                    package main
                    import "fmt"
                    func main() {
                    	//定义管道
                    	var intChan chan int
                    	intChan =make(chan int,3)
                    	//写入数据
                    	intChan<-10
                    	intChan<-20
                    	intChan<-30
                    	//遍历
                    	close(intChan) //关闭管道
                    	for value := range intChan {
                    		fmt.Printf("%d\t",value) //10	20	30	
                    	}
                    }
                    

                    管道注意事项

                    -`channel可以声明为只读,或者只写性质

                      使用select可以解决从管道取数据的阻塞问题goroutine中使用recover,解决协程中出现panic,导致程序崩溃问题

                      综合案例

                      package main
                      import "fmt"
                      func main() {
                      	numChan := make(chan int, 2000)
                      	resChan := make(chan int, 2000)
                      	exitChan := make(chan bool, 8)
                      	go putNum(numChan) //存放数据
                      	//开启八个协程
                      	for i := 0; i < 8; i++ {
                      		go add(numChan, resChan, exitChan)
                      	}
                      	go func() {
                      		for i:=0;i<8 ;i++  {
                      			<-exitChan
                      		}
                      		close(resChan)
                      	}()
                      	for i := 1; i <=2000 ; i++ {
                      		fmt.Printf("resChan[%d]=%d\n", i, <-resChan)
                      	}
                      }
                      func putNum(numChan chan int) {
                      	for i := 1; i <= 2000; i++ {
                      		numChan <- i
                      	}
                      	close(numChan)
                      }
                      func add(numChan chan int, resChan chan int, exitChan chan bool) {
                      	for {
                      		n,ok := <-numChan
                      		if !ok{
                      			break
                      		}
                      		res := 0
                      		for i := 1; i <= n; i++ {
                      			res += i
                      		}
                      		resChan <- res
                      	}
                      	exitChan<-true
                      }
                      

                      以上就是Go语言Goroutinue和管道效率详解的详细内容,更多关于Go Goroutinue 管道效率的资料请关注易采站长站其它相关文章!