golang的线程模型

golang的线程模型_第1张图片


多线程和多进程存在的问题是耗费内存,线程切换
其他语言的协程: php-swoole java-netty
协程优势:切换快 内存占用小(2k)

  • golang的线程模型是GMP模型
    • 在语言层面是没有开放线程的但是在运行时候M个线程可以创建N个goroutine,一般N远大于M本质属于多线程模型,但是协程的调用由goruntine决定,强调开发者应该使用channel进行协程之间的同步
  • GMP模型
    • goroutine在M个线程上运行,每次执行任务都会去查当前P(处理器)上的可执行队列,队列里面就是可以执行的goroutine,一旦当前P上没有可供执行的它就会去窃取另一个P的可执行队列中的goroutine。而goroutine的创建理论上来说只受内存限制,一般而言最大也就2KB,对于一个线程2MB空间大小理论上来说可以轻易上1000个,当然这只是理想情况下,所以OS线程数不会随着goroutine创建个数增加而增加。线程调度是对于go来说会比较耗费性能,频繁切换调度只会在goroutine之间存在,线程只会保持与cpu数相同的活跃线程数。
  • 协程切换
    • 如果协程阻塞有一些需要占用M处理资源(读取文件等操作)的时候会P(处理器)会将他挂起一个M(线程)阻塞,P就会去创建或者切换另一个M继续执行队列中后续的goroutine
package main

import (
	"fmt"
	"time"
)

/**
并发编程
 */
//主协程
func main() {

	//启动子协程,通过go关键字启动协程
	go asyncPrint()
	//匿名函数方式启动协程
	go func() {
		i := 1
		for{
			fmt.Println("async print2 ",i)
			i++
			if i>100 {
				return
			}
		}
	}()//最后一个括号是执行的意思func(){}只是定义

	//1.
	for i:=0;i<100;i++{
		//闭包导致里面主函数里面的匿名函数可以使用主函数的变量
		go func() {
			j := 1
			//for{
				//1.这里打印,i的值会因为外面的循环i++导致靠前的值不会打印因为i没有进行复制,和外面还是用的同一个变量,变量指向的堆中的值还是一样的,导致外面改变了堆中的值这里也会收到影响,
				//2.并且打印乱是因为多个协程执行顺序可能不一样
				//3.将其复制
				tmp := i
				fmt.Println(i,"async print3 ",j,tmp)
				j++
			//}
		}()

		//4.使用值传递方式
		go func(i int) {
			j := 1
			tmp := i
			fmt.Println(i,"async print4 ",j,tmp)
			j++
		}(i)
	}

	fmt.Println("main ok")
	//这里存在主死随从,所以主协程需要等子协程执行完
	time.Sleep(2*time.Second)

}

func asyncPrint(){
	i := 1
	for{
		fmt.Println("async print1 ",i)
		i++
		if i>100 {
			return
		}
	}
}
 

你可能感兴趣的:(golang,协程,线程模型)