Bruce Blog Bruce Blog
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航

Bruce Tao

运维界的该溜子
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航
  • 基础

  • Go进阶

    • Go进阶
    • File操作
    • IO操作
    • 文件复制
    • 断点续传
    • bufio包
    • ioutil包
    • 遍历目录
    • 并发性Concurrency概念
    • Goroutine初识
      • Goroutine并发模型
      • Runtime包
      • 临界资源安全问题
      • sync包WaitGroup
      • 互斥锁
      • 读写锁
      • Channel通道
      • 关闭通道和通道上范围循环
      • 缓冲通道
      • 定向通道
      • time包中的通道相关函数
      • select语句
      • CSP并发模型
      • Go语言反射(一)
      • Go语言反射(二)
    • Go框架

    • Golang辅助

    • Golang
    • Go进阶
    Bruce
    2022-12-03
    目录

    Goroutine初识

    # 一、Go语言的协程 --- Goroutine

    进程(Process)、线程(Thread)、协程(Coroutine,也叫轻量线程)

    进程 进程是一个程序在一个数据集中的一次动态执行过程,可以简单理解为"正在执行的程序",它是CPU资源分配和调度的独立单位.进程一般由程序、数据集、进程控制块三部分组成.在编写程序用来描述要完成哪些功能以及如何完成;数据集则是程序执行过程中所需要使用的资源;进程空间块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志.进程吧局限是创建、撤销和切换的开销比较大

    线程 线程是在进程之后发展出来的概念.线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成.一个进程可以包含多个线程.线程的优点是减小了程序并发执行时的开销,提高了操作系统的并发性能,缺点是线程没有自己的系统资源,只拥有在运行时必不可少的资源,但同一进程的各线程可以共享进程所拥有的系统资源,如果把进程比作一个车间,那么线程就好比是车间里面的工人.不过对于某些独占性资源存在锁机制,处理不当可能会产生"死锁"

    协程 协程是一种用户态的轻量级线程,又称微线程,英文名字Coroutine,协程的调用完全由用户控制.人们通常将协程和子程序(函数)比较着好理解.子程序总是一个入口,一次返回,一旦退出即完成了子程序的执行.

    比起传统的系统线程和进程相比,协程的最大优势在于其"轻量级",可以轻松创建上百万个而不会导致系统资源衰竭,而线程和进程通常最多也不能超过1万的.这也是协程也叫轻量级线程的原因.

    协程与多线程相比,其优势体现在: 协程的执行效率极高.因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显.

    # 二、Goroutine

    # 什么是Goroutine

    go中使用Goroutine来实现并发concurrently

    Goroutine是Go语言特有的名词.区别与进程Process,线程Thread,协程Coroutine,因为Go语言的创造者们觉得和他们是有所区别的,所以专门创造了Goroutine

    Goroutine是与其他函数或方法同时运行的函数或方法.Goroutine可以被认为是轻量级的线程.与线程相比,创建Goroutine的成本很小,它就是一段代码,一个函数入口.以及在堆上为其分配的一个堆栈(初始大小为4K,会随着程序的执行自动增长删除).因此它非常廉价,Go应用程序可以并发运行数千个Goroutine

    Goroutine在线程上的优势.

    1.与线程相比,Goroutine非常便宜,它们只是堆栈大小的几个kb,堆栈可以根据应用程序的需要增长和收缩,而在线程的情况下,堆栈大小必须指定并且是固定的.

    2.Goroutine被多路复用到较少的OS线程.在一个程序中可能只有一个线程与数千个Goroutines.如果线程中的任何Goroutine都表示等待用户输入,则会创建另一个OS线程,剩下的Goroutines被转移到新的OS线程.所有这些都由运行时进行处理,作为程序员从这些复杂的细节中抽象出来,并得到了一个与并发工作相关的干净的API

    3.当使用Goroutine访问共享内存时,通过设计的通道可以防止竞态条件发生.通道可以被认为是Goroutines通信的管道.

    # 主goroutine

    封装main函数的goroutine称为主goroutine

    主goroutine所做的事情并不是执行main函数那么简单.它首次要做的是: 设定每一个goroutine所能申请的栈空间的最大尺寸.在32为计算机系统中此最大尺寸为250M,而在64的计算机系统中此尺寸为1GB.如果有某个goroutine的栈空间尺寸大于这个限制,那么运行时系统就会引发一个栈溢出(stack overflow)的运行时恐慌.随后,这个go程序的运行也会终止.

    此后,主goroutine会进行一系列的初始化工作,涉及的工作内容如下:

    • 1.创建一个特殊的defer语句,用于在主goroutine退出时必要的善后处理.因为主goroutine也可能非正常的结束

    • 2.启动专用与在后台清理内存垃圾的goroutine,并设置GC可用的标识

    • 3.执行main包中的init函数

    • 4.执行main函数

      执行完main函数后,它还会检查主goroutine是否引发运行时恐慌,并进行必要的处理.最后主goroutine会结束自己以及当前进程的运行.

    # 如何使用Goroutines

    在函数或方法调用前面加上关键字go,这将会同时运行一个新的Goroutine

    示例代码:

    package main
    
    import (
    	"fmt"
    )
    
    func hello(){
        fmt.Println("Hello world goroutine")
    }
    
    func main() {
        go hello()
        fmt.Println("main function")
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    运行结果:

    • 可能会只输出"main function"

    image-20221123145423101

    • Goroutine规则

      1.当新的Goroutine开始时,Goroutine调用立即返回.与函数不同,go不等待Goroutine执行结束.当Goroutine调用,并且Goroutine的任何返回值被忽略之后,go立即执行到下一行代码.

      2.main的Goroutine应该为其他的Goroutine执行.如果main的Goroutine终止流量,程序将被终止,而其他Gortouine将不会运行.

    修改代码:

    package main
    
    import (  
        "fmt"
        "time"
    )
    
    func hello() {  
        fmt.Println("Hello world goroutine")
    }
    func main() {  
        go hello()
        time.Sleep(1 * time.Second)
        fmt.Println("main function")
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    运行结果:

    image-20221123150728416

    在上面的程序中,已经调用了时间包的Sleep方法,它会在执行过程中睡觉.在这种情况下,main的goroutine被用来睡觉1秒.现在调用go hello()有足够的时间在main Groutine终止之前执行.这个程序首先打印Hello world goroutine,等待1秒,然后打印main函数.

    # 启动多个Goroutines

    示例代码

    package main
    
    import (  
        "fmt"
        "time"
    )
    
    func numbers() {  
        for i := 1; i <= 5; i++ {
            time.Sleep(250 * time.Millisecond)
            fmt.Printf("%d ", i)
        }
    }
    func alphabets() {  
        for i := 'a'; i <= 'e'; i++ {
            time.Sleep(400 * time.Millisecond)
            fmt.Printf("%c ", i)
        }
    }
    func main() {  
        go numbers()
        go alphabets()
        time.Sleep(3000 * time.Millisecond)
        fmt.Println("main terminated")
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    运行结果:

    image-20221123151759845

    时间轴分析

    image-20221123155210246

    上次更新: 2024/04/09, 16:48:42
    并发性Concurrency概念
    Goroutine并发模型

    ← 并发性Concurrency概念 Goroutine并发模型→

    最近更新
    01
    AWS NAT-NetWork-Firwalld配置(一)
    04-09
    02
    AWS NAT-NetWork-Firwalld配置(二)
    04-09
    03
    kubernetes部署minio对象存储
    01-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Bruce Tao Blog Space | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式