深入解析 Go 语言 GMP 模型:并发编程的焦点机制

十念  金牌会员 | 2024-7-30 12:27:26 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 887|帖子 887|积分 2661

前言

本章是Go并发编程的起始篇章,在未来几篇文章中我们会围绕Go并发编程进行理论和实战的学习,欢迎关注我哦!
本章主要以先容GMP模型为主,偏向于面试和八股,目标是让小伙伴们注重于知识本身,面向面试,面向八股,面向加薪。
Go语言自诞生以来,就以其简洁、高效的并发模型著称。而这其中的焦点正是GMP模型。理解GMP模型的演进进程,能资助我们更好地掌握Go的并发编程。而Goroutine作为Go中的焦点概念,极大地简化了并发编程的复杂度。本文将详细阐述Go语言GMP模型的演变过程,并深入解析其设计理念和优点,并详细先容Goroutine的根本概念、优势及其使用方法,并结合具体代码示例进行说明。
面试标题

在阅读本文前,先带着以下几个关于GMP模型的面试标题进行思考,以加深理解和掌握:

  • 什么是GMP模型?请表明其根本概念。


  • 回答要点:表明G、M、P的概念及其在调度模型中的角色。

  • 如何理解GMP模型中线程的内核态和用户态?


  • 回答要点:区分内核态线程和用户态线程,并说明它们在GMP模型中的作用。

  • Go语言中的Goroutine与线程的映射关系是怎样的?为什么选择这种映射方式?


  • 回答要点:表明Goroutine与线程的多对多映射关系及其优点。

  • GMP模型如何解决线程调度中的锁竞争问题?


  • 回答要点:先容全局队列和本地队列的使用,以及G的分配机制。

  • GMP模型中的Stealing机制是什么?它如何工作?


  • 回答要点:形貌Stealing机制的原理及其在Goroutine调度中的应用。

  • 什么是Hand off机制?在什么情况下会使用该机制?


  • 回答要点:表明Hand off机制及其在阻塞和系统调用中的应用。

  • 如何理解GMP模型中的抢占式调度?它解决了哪些问题?


  • 回答要点:说明抢占式调度的原理及其在防止协程饿死中的作用。

  • 什么是G0和M0?它们在GMP模型中饰演什么角色?


  • 回答要点:形貌G0和M0的界说及其在Goroutine调度中的功能。

  • 请详细说明GMP模型中的调度策略。


  • 回答要点:逐步表明Goroutine的创建、唤醒、偷取、切换、自旋、系统调用和阻塞处置惩罚策略。

  • 如安在实际项目中调优GMP调度模型?


  • 回答要点:讨论如何通过调解GOMAXPROCS等参数来优化调度性能。
带着这些问题阅读本文,可以资助你更系统地掌握GMP模型的焦点概念和调度机制,提高面试中的应答能力。
单进程时代

根本概念

在单进程时代,一个进程就是一个运行中的程序。计算机系统在执行程序时,会重新到尾依次执行完一个程序,然后再执行下一个程序。在这种模型中,不必要复杂的调度机制,因为只有一个执行流程。
面对的两个问题


  • 单一执行流程:由于只能一个个执行程序,无法同时处置惩罚多个任务,这大大限定了CPU的使用率。
  • 进程阻塞:当一个进程遇到I/O操纵等阻塞情况时,CPU资源会被浪费,等待进程完成阻塞操纵后再继续执行,导致效率低下。
多进程/线程并发时代

根本概念

为了解决单进程时代的效率问题,引入了多进程和多线程并发模型。在这种模型中,当一个进程阻塞时,CPU可以切换到另一个准备好的进程继续执行。这样可以充分使用CPU资源,提高系统的并发处置惩罚能力。
两个问题


  • 高开销:进程拥有大量资源,进程的创建、切换和销毁都必要消耗大量的时间和资源。这导致CPU很大一部门时间都在处置惩罚进程调度,而不是实际的任务执行。
  • 高内存占用:在32位机器下,进程的虚拟内存占用为4GB,线程占用为4MB。大量的线程和进程会导致高内存消耗,限定了系统的扩展性。
协程的引入

为了解决多进程和多线程带来的高开销和高内存占用问题,引入了协程(Coroutine)。协程是一种比线程更轻量级的执行单元。协程在用户态进行调度,避免了频繁的上下文切换带来的开销。Go语言的GMP模型正是基于协程的设计。
协程的根本概念

在深入了解Goroutine之前,先来了解一下协程(Coroutine)的根本概念。
内核态和用户态


  • 内核态线程:由操纵系统管理和调度,CPU只负责处置惩罚内核态线程。
  • 用户态线程:由用户程序管理,需绑定到内核态线程上执行,协程即为用户态线程的一种。

内核态和用户态线程关系图


  • Kernel Space(内核空间):上半部门的灰色区域,表示操纵系统管理的内核空间。
  • User Space(用户空间):下半部门的白色区域,表示用户程序运行的空间。
  • Kernel Thread 1 和 Kernel Thread 2(内核线程):由操纵系统管理的内核线程,CPU直接处置惩罚这些线程。
  • User Thread 1、User Thread 2 和 User Thread 3(用户线程):由用户程序管理的用户线程(协程),需绑定到内核线程上执行。
执行流程


  • 用户态线程:

    • 用户程序创建多个用户线程(如协程),如图中的“User Thread 1”、“User Thread 2”和“User Thread 3”。

  • 内核态线程:

    • 用户线程需绑定到内核态线程上执行,如图中的“Kernel Thread 1”和“Kernel Thread 2”。

  • CPU处置惩罚:

    • CPU只处置惩罚内核态线程,通过绑定关系,用户态线程的执行也依赖于内核态线程的调度。
    • 图中的赤色箭头表示CPU正在处置惩罚内核线程,从而间接处置惩罚绑定的用户线程。

线程和协程的映射关系


  • 单线程绑定所有协程

    • 问题1:无法使用多核CPU的能力。
    • 问题2:假如某个协程阻塞,整个线程和进程都将阻塞,导致其他协程无法执行,丧失并发能力。

  • 一对一映射

    • 将每个协程绑定到一个线程上,退回到多进程/线程的模式,协程的创建、切换、销毁均需CPU完成,效率低下。

  • 多对多映射

    • 允许多个协程绑定到多个线程上,形成M:N的关系。这样可以充分使用多核CPU,并通过协程调度器高效管理协程的执行。


Goroutine

Goroutine是Go语言中的协程,实现了轻量级并发。与传统的线程相比,Goroutine具有以下显著特点:
轻量级

Goroutine非常轻量,初始化时仅占用几KB的栈内存,并且栈内存可以根据必要动态伸缩。这使得我们可以在Go程序中创建成千上万个Goroutine,而不会消耗过多的系统资源。
高效调度

Goroutine的调度由Go语言的运行时(runtime)负责,而不是操纵系统。Go运行时在用户态进行调度,避免了频繁的上下文切换带来的开销,使得调度更加高效。
Goroutine的使用示例

下面是一个简朴的示例,展示了如安在Go语言中使用Goroutine进行并发编程。
  1. package main
  2. import (
  3.     "fmt"
  4.     "time"
  5. )
  6. func say(s string) {
  7.     for i := 0; i < 5; i++ {
  8.         time.Sleep(100 * time.Millisecond)
  9.         fmt.Println(s)
  10.     }
  11. }
  12. func main() {
  13.     go say("Hello")
  14.     go say("World")
  15.     time.Sleep(1 * time.Second)
  16.     fmt.Println("Done")
  17. }
复制代码
在这个示例中,两个Goroutine同时执行,分别打印"Hello"和"World"。通过使用go关键字,我们可以轻松地启动一个新的Goroutine。
必要注意的事项


  • 主Goroutine的竣事:在Go程序中,main函数本身也是一个Goroutine,称为主Goroutine。当主Goroutine竣事时,所有其他Goroutine也会随之终止。因此,必要确保主Goroutine等待所有子Goroutine执行完毕。
  • 同步和共享数据:固然Goroutine之间共享内存空间,但必要通过同步机制(如通道和锁)来避免竞争条件。Go语言保举使用通道(channel)进行Goroutine之间的通讯,以保证数据的安全性和同步性。
示例:使用通道进行同步

下面的示例展示了如何使用通道来同步多个Goroutine的执行。
[code]package mainimport (    "fmt"    "sync")func worker(id int, wg *sync.WaitGroup) {    defer wg.Done()    fmt.Printf("Worker %d starting\n", id)    // 模仿工作    fmt.Printf("Worker %d done\n", id)}func main() {    var wg sync.WaitGroup    for i := 1; i

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表