golang-goroutine(协程)和channel(管道)

在这里插入图片描述
传统进程和线程概念介绍:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
并发和并行概念介绍:
在这里插入图片描述
在这里插入图片描述


golang协程(goroutine)

golang协程的特点

  • 有独立的栈空间(栈可理解为数值类型,由堆中copy或引用到个体栈空间)
  • 共享程序堆空间(堆可理解为引用数据类型)
  • 调度由用户控制(线程启动和停止都可由用户控制,java则不行 )
  • 协程是轻量级的线程(理论上轻松可启上万条线程)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
package main

import (
	"fmt"
	"strconv"
	"time"

)
func goroutine(){
   
	for i:=1;i<=10;i++{
   
		fmt.Println("hello world" + strconv.Itoa(i))
		time.Sleep(time.Second)
	}
}

func main(){
   
	// 开启一个协程
	go goroutine()

	for i:=1;i<=10;i++{
   
		fmt.Println("hello goroutine" + strconv.Itoa(i))
		time.Sleep(time.Second)
	}
}

PowerShell输出:

PS E:\...\src\gojson\jsondemo-10-24\goroutine> go run .\main.go     
hello world1
hello goroutine1
hello goroutine2
hello world2
hello world3
hello goroutine3
hello goroutine4
hello world4
hello world5
hello goroutine5
hello goroutine6
hello world6
hello world7
hello goroutine7
hello goroutine8
hello world8
hello world9
hello goroutine9
hello goroutine10
hello world10

go协程执行过程:
在这里插入图片描述
go协程总结:
在这里插入图片描述

  • go协程一般是以函数为单位的
  • 协程依托于主线程执行,主线程执行完毕或停止退出则协程也直接退出,即使没有执行完毕,若协程先于主线程执行完毕则主线程继续执行完毕
  • go协程中,主线程可以理解为类似进程,协程类似于线程

goroutine调度模型MPG

  • M:主线程,直接运行在操作系统上,为物理线程
  • P:程序运行需要的资源或者说依赖
  • G:协程是一个逻辑程序依赖于M主线程 运行,有自己的栈独立运行
  • M可以有多个,多个M运行在一个cpu上叫做并发,多个M运行在多个cpu叫做并行
  • 如果一个协程发生了阻塞程序会另外开启一个线程把排队的协程引用到这个新开启的M中去,等到M0中的G不再堵塞则再进行M0的调度执行,保证程序得以继续并发执行
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

golang中设置允许cpu数目
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package main

import (
	"fmt"
	"runtime"
)

func main(){
   
	// runtime.NumCPU() 查看本机有几颗逻辑cpu
	cpunum := runtime.NumCPU()
	fmt.Println(cpunum)

	// runtime.GOMAXPROCS() 可以设置可同时执行最大cpu数目
	runtime.GOMAXPROCS(cpunum-1)
	
	// runtime.Version() 返回go版本字符串,1.8以后默认多核允许不需要设置
	govarson := runtime.Version()
	fmt.Println(govarson)
}
PS E:\...\src\gojson\jsondemo-10-24\cupdemo> go run .\main.go                                     
2
go1.9.2

在这里插入图片描述

channel管道

在这里插入图片描述
多个协程资源竞争问题:

  • 下边这个程序我们通过一个 test() 函数,计算传入参数的阶乘并写入map中,主函数里开启200个协程来进行相应阶乘运算此时由于多个协程同时往一个map中写入数据就会出错,资源占用冲突
package main

import (
	"fmt"
	"time"
)

var mymap = make(map[int]int,10)

func test(n int){
   

	res := 1
	for i:=1;i<=n;i++{
   
		res *= i
	}
	mymap[n] = res
}

func main(){
   
	// 通过循环开启200个协程
	for i:=0;i<200;i++{
   
		go test(i)
	}

	// 休眠十秒钟
	time.Sleep(time.Second * 10)
	for k,v := range mymap{
   
		fmt.Println(k,v)
	}
}

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • Mutex是一个结构体,有各种绑定这个结构体的方法,如 lock() ,将传入的参数锁住,Unlock() 方法可以解锁,锁和线程无关可以由任何线程加锁和解锁

在这里插入图片描述

package main

import (
	"fmt"
	"time"
	// "sync"
)

var (
	// int类型默认为int64位大小为 2的63次方减一等于9223372036854776000
	// 也就是说只能存放这么大的数字超出范围置为0
	mymap = make(map[int]int)
	// 实例化sync.Nutex这个struct,以便使用绑定这个struct的方法
	// 这里也是一个小技巧,实例化结构体
	lock sync.Mutex
)

func test(n int){
   

	res := 1
	for i:=1;i<=n;i++{
   
		res *= i
	}
	// 加锁
	lock.
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值