go语言goroutine
Go语言goroutine
在别的语言里想要在一个程序中实现多任务,如python,python实现多任务可以使用多进程、多线程、携程。但多进程占用资源,多线程无法发挥多核的优势(GIL),python的协程是单线程的,必须等一个任务作出让步,另一个任务才能执行,如果其中一个任务阻塞住,让不出cpu来,那么整个程序都会被阻塞住。
go语言的goroutine(协程)是一个类似于线程的概念,但是它比线程轻量。当开启了多个goroutine后,程序会将每个goroutine分配给每个cpu的核心,可以充分发挥cpu多核的效率。go的协程效率比为m(cpu核数)/n(goroutine数),而python的协程的效率比为1/n
开启goroutine
只需要在将任务封装成一个函数,使用go关键字,就可以开启一个goroutine完成多任务。同时,程序的主函数也是一个goroutine
package main
import "fmt"
func work() {
fmt.Printf("work goroutine")
}
func main() {
go work()
fmt.Println("main goroutine")
}
sync.WaitGroup
上面的程序启动goroutine是没问题,但是编译运行后会发现只有打印了main goroutine。这是因为,开启在主goroutine里面启动另外一个goroutine后,另外开启的goroutine还没来得及运行,主goroutine就已经结束了,主goroutine结束,由主goroutine中开启的goroutine全部都会结束,所有主goroutine想要其他的goroutine执行,必须得等待。
package main
import (
"fmt"
"time"
)
func work() {
fmt.Println("work")
}
func main() {
go work()
fmt.Println("main goroutine")
time.Sleep(time.Second)
}
使用time.Sleep来是程序休眠,来达到让另外goroutine由充足的时间来运行
但是当开启了多个goroutine后,我们不知道全部的协程运行完毕需要多少时间,我们就无法估量sleep的时间。sleep的时间可能多了,可能少了,少了就会让能成达不到想要的目的,多了就会让程序多休眠,浪费资源,此时,就需要引入sync模块的工具来解决这个问题
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func work() {
defer wg.Done()
fmt.Println("work")
}
func main() {
wg.Add(1)
go work()
fmt.Println("main goroutine")
wg.Wait() // 等待所有的协程能全部运行完毕
}
使用sync.WaitGroup,当需要开启一个协程前,往WaitGroup里面加1,在协程结束后,向WaitGroup告知已经完成(可以配合defer 关剪字使用),最后在主goroutine(main函数)的最后使用WaitGroup来等待所有的goroutine运行结束(对应的函数执行结束)
goroutine和线程的关系
这里的线程指的是操作系统的线程,线程和goroutine启动占用的资源不一样,线程的栈内存一般为2mb,而goroutine在开始的时候占用的栈内存为2kb,goroutine的栈不是固定的,它可以像go的切片一样扩容,最大限制可以达到一个G,所有在go里面可以很容易开启十万个goroutine。
- GMP调度
- G:G代表goroutine,里面存放当前的goroutine的信息和当前goroutine所载的P的绑定等信息
- M:M是go运行时对操作系统的线程的虚拟。一个goroutine最终都是要放在M上运行的
- P:P管理者一组goroutine队列,P里面存放着当前的goroutine的上下文,P会对当前管理的goroutine队列做一些调度(某些goroutine可能占用cpu时间过长,P会将这个goroutine暂停,然后去让别的goroutine来执行)。当自己的goroutine全部运行结束了,这个P会去全局的队列里面取,如果全局的里面也没有了,它甚至会去别的P里面取获取goroutine,这样可以实现效率的最大化
- P与M一般也是一一对应的。他们关系是: P管理着一组G挂载在M上运行。当一个G长久阻塞在一个M上时,runtime会新建一个M,阻塞G所在的P会把其他的G 挂载在新建的M上。当旧的G阻塞完成或者认为其已经死掉时 回收旧的M。
go语言goroutine的更多相关文章
- TODO:Go语言goroutine和channel使用
TODO:Go语言goroutine和channel使用 goroutine是Go语言中的轻量级线程实现,由Go语言运行时(runtime)管理.使用的时候在函数前面加"go"这个 ...
- Go语言goroutine调度器初始化(12)
本文是<Go语言调度器源代码情景分析>系列的第12篇,也是第二章的第2小节. 本章将以下面这个简单的Hello World程序为例,通过跟踪其从启动到退出这一完整的运行流程来分析Go语言调 ...
- Go语言goroutine调度器概述(11)
本文是<go调度器源代码情景分析>系列的第11篇,也是第二章的第1小节. goroutine简介 goroutine是Go语言实现的用户态线程,主要用来解决操作系统线程太“重”的问题,所谓 ...
- Go语言 - goroutine
并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天). 并行:同一时刻执行多个任务(你和你朋友都在用微信和女朋友聊天). Go语言的并发通过goroutine实现.goroutin ...
- Go语言 | goroutine不只有基础的用法,还有这些你不知道的操作
今天是golang专题第15篇文章,我们来继续聊聊channel的使用. 在我们的上篇文章当中我们简单介绍了golang当中channel的使用方法,channel是golang当中一个非常重要的设计 ...
- Go语言学习之8 goroutine详解、定时器与单元测试
主要内容: 1.Goroutine2. Chanel3. 单元测试 1. Goroutine Go 协程(Goroutine)(轻量级的线程,开线程没有数量限制). (1)进程和线程 A. 进程是 ...
- 09. Go 语言并发
Go 语言并发 并发指在同一时间内可以执行多个任务.并发编程含义比较广泛,包含多线程编程.多进程编程及分布式程序等.本章讲解的并发含义属于多线程编程. Go 语言通过编译器运行时(runtime),从 ...
- 分布式 基本理论 BASE
比起CAP的生硬来, 我更加喜欢BASE.BASE 显得更加好理解.尽管BASE 这个名字本身有迎合语言习惯的恶臭味,为什么不是缩写为 BaSsEc 呢? 其实大部分系统是可以 同时 CAP 的, 因 ...
- golang 学习笔记 ---内存分配与管理
Go语言——内存管理 参考: 图解 TCMalloc Golang 内存管理 Go 内存管理 问题 内存碎片:避免内存碎片,提高内存利用率. 多线程:稳定性,效率问题. 内存分配 内存划分 are ...
随机推荐
- Simulink仿真入门到精通(十二) Publish发布M文件
12.1 M文件的注释 使用%进行注释. 连续多行注释Ctrl+R,取消注释Ctrl+T. 12.2 Cell模式 在MATLAB脚本文件中使用连续两个注释符,开启一个新的Cell块,%%后空一格追加 ...
- 事务特性,事务的隔离级别以及spring中定义的事务传播行为
.katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...
- fastdfs的入门到精通(引言和单机安装)
引言: FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的在线服 ...
- js 实现弹性运动的简单应用----导航栏中弹性
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Angular入门之环境搭建(VS code)(转载)
安装Visual Studio Code VS code和我们常用的VS压根不是一回事,它只是一个开源的轻量级编辑器,而不是IDE,因为支持typescript语法,且插件功能丰富,所以选择 官网下载 ...
- Zetatier One 基本用法
Zetatier One 基本用法 ZeroTier One是用加密的点对点技术将处于不同物理位置的网络建立私人的局域网,即使用软件实现路由和交换机功能,而且它能使用WEB控制台管理网络,是对SDN( ...
- mysql & Tomcat使用问题记录
mysql使用问题记录 1.mysql如何修改root密码 a.进入mysql安装目录b.登录 mysql -u root -pc.修改密码 mysql> SET PASSWORD FOR ro ...
- cmdb客户端采集数据的完善
file文件自己去拷贝(这里不提供) custom_settings.py import os BASEDIR = os.path.dirname(os.path.dirname(os.path.ab ...
- 题解 P2755 【洗牌问题】
这是本人的第一篇题解 请多多宽恕 这一道题其实不要用数组 我们来观察一下n=3时的情况: 原: 1 2 3 4 5 6 4 1 5 2 6 3 2 4 6 1 3 5 1 2 3 4 5 6 我们去观 ...
- java获取不同时段
当前时间: long currentime= System.currentTimeMillis(); 本周第一天0时: Long weekstart = current.withDayOfWeek(1 ...