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的更多相关文章

  1. TODO:Go语言goroutine和channel使用

    TODO:Go语言goroutine和channel使用 goroutine是Go语言中的轻量级线程实现,由Go语言运行时(runtime)管理.使用的时候在函数前面加"go"这个 ...

  2. Go语言goroutine调度器初始化(12)

    本文是<Go语言调度器源代码情景分析>系列的第12篇,也是第二章的第2小节. 本章将以下面这个简单的Hello World程序为例,通过跟踪其从启动到退出这一完整的运行流程来分析Go语言调 ...

  3. Go语言goroutine调度器概述(11)

    本文是<go调度器源代码情景分析>系列的第11篇,也是第二章的第1小节. goroutine简介 goroutine是Go语言实现的用户态线程,主要用来解决操作系统线程太“重”的问题,所谓 ...

  4. Go语言 - goroutine

    并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天). 并行:同一时刻执行多个任务(你和你朋友都在用微信和女朋友聊天). Go语言的并发通过goroutine实现.goroutin ...

  5. Go语言 | goroutine不只有基础的用法,还有这些你不知道的操作

    今天是golang专题第15篇文章,我们来继续聊聊channel的使用. 在我们的上篇文章当中我们简单介绍了golang当中channel的使用方法,channel是golang当中一个非常重要的设计 ...

  6. Go语言学习之8 goroutine详解、定时器与单元测试

    主要内容: 1.Goroutine2. Chanel3. 单元测试 1. Goroutine Go 协程(Goroutine)(轻量级的线程,开线程没有数量限制).   (1)进程和线程 A. 进程是 ...

  7. 09. Go 语言并发

    Go 语言并发 并发指在同一时间内可以执行多个任务.并发编程含义比较广泛,包含多线程编程.多进程编程及分布式程序等.本章讲解的并发含义属于多线程编程. Go 语言通过编译器运行时(runtime),从 ...

  8. 分布式 基本理论 BASE

    比起CAP的生硬来, 我更加喜欢BASE.BASE 显得更加好理解.尽管BASE 这个名字本身有迎合语言习惯的恶臭味,为什么不是缩写为 BaSsEc 呢? 其实大部分系统是可以 同时 CAP 的, 因 ...

  9. golang 学习笔记 ---内存分配与管理

    Go语言——内存管理 参考: 图解 TCMalloc Golang 内存管理 Go 内存管理 问题 内存碎片:避免内存碎片,提高内存利用率. 多线程:稳定性,效率问题. 内存分配   内存划分 are ...

随机推荐

  1. 基于Redis未授权访问的挖矿蠕虫分析

    0x01 攻击方式 利用的是通用漏洞入侵服务器并获得相关权限,从而植入挖矿程序再进行隐藏. 通过对脚本的分析,发现黑客主要是利用 Redis未授权访问漏洞进行入侵.脚本里有个python函数. imp ...

  2. springBoot启动后 http://localhost:8080 地址无法访问

    http://localhpost:8080/hello 代码结构: 代码内容: @RestController public class HelloWordRestImpl implements H ...

  3. css定位属性的运用

    position 定位定位:主要解决叠加排列的问题.position 1.static(默认) 2.relative : 相对定位 如果没有定位偏移量,对元素本身没有任何影响(一般用于需要加定位的父容 ...

  4. mysql刷题(不定时更新)

    面试阶段大家基本都会问一些mysql的题,具体的高深理论以后再慢慢补充,但是刷题是不可避免的,下面直接上货 创建/删除表和索引系列 创建表 CREATE TABLE if not exists `te ...

  5. Spring 全局异常拦截根据业务返回不同格式数据 自定义异常

    1.全局异常拦截:针对所有异常进行拦截 可根据请求自定义返回格式 2.自定义异常类 处理不同业务的异常 接下来开始入手代码: 1).自定义异常类 @ControllerAdvice//添加注解 记得开 ...

  6. Android开发:通过 webview 将网页打包成安卓应用

    商业转载请联系作者获得授权,非商业转载请注明出处. For commercial use, please contact the author for authorization. For non-c ...

  7. Mysql5.7及以上版本 ONLY_FULL_GROUP_BY报错

    近期在开发过程中,因为项目开发环境连接的mysql数据库是阿里云的数据库,而阿里云的数据库版本是5.6的.而测试环境的mysql是自己安装的5.7.因此在开发过程中有小伙伴不注意写了有关group b ...

  8. 最小生成树的Prim算法以及Kruskal算法的证明

    Prime算法的思路:从任何一个顶点开始,将这个顶点作为最小生成树的子树,通过逐步为该子树添加边直到所有的顶点都在树中为止.其中添加边的策略是每次选择外界到该子树的最短的边添加到树中(前提是无回路). ...

  9. 基础的linux命令(一)

    我练习使用的 Linux 系统是 CentOS 7 它是通过把 RHEL 系统重新编译并发布给用户免费使用的 Linux 系统. 首先你需要一台Linux虚拟机,如果没有,也没关系,点这里 一.命令格 ...

  10. windows10环境下QtCreator中出现skipping incompatible xxx when searching for xxx 问题解决办法

    windows10环境下QtCreator中出现skipping incompatible xxx when searching for xxx 我再QtCreator中想导入一个外部库时,他提示不匹 ...