当前位置: 首页 > article >正文

Golang协程为什么⽐线程轻量

Golang协程(goroutine)比线程轻量,主要归因于以下几个关键因素:

一、初始堆栈大小与动态调整

  • 线程:每个系统线程的堆栈大小通常很大,通常在2MB左右,且这些堆栈大小通常是固定的,不能根据需求动态改变。
  • 协程:Go协程的初始堆栈大小远小于线程,只有2KB左右。更重要的是,Go协程的堆栈是动态的,可以根据需求增长和缩小。当堆栈空间不够时,Go运行时可以自动增加其大小;当堆栈空间过大时,也可以自动缩小。这种动态调整机制避免了内存浪费,使得创建大量协程所需的内存远少于创建相同数量的线程。

二、调度模型与开销

  • 线程:线程的调度由操作系统负责,创建、销毁和上下文切换都需要系统调用的参与,因此开销较大。线程切换会触发用户态和内核态的切换,上下文切换的延迟较高,大约是50到100纳秒(ns)左右。
  • 协程:Go协程由Go运行时而非操作系统进行调度,因此调度开销更小。Go运行时使用M:N的调度模型,其中M个goroutine可以在N个OS线程上进行调度。这使得Go可以在用户级别实现轻量级的上下文切换,避免了频繁的系统调用和线程切换。此外,Go将goroutine的调度维持在用户态,由GPM中的P(逻辑处理器)来完成调度任务,这个切换只涉及PC(程序计数器)、SP(堆栈指针)、DX(数据寄存器)三个寄存器的值的修改,相比线程的上下文切换(需要陷入内核模式以及16个寄存器的刷新)要轻量得多。

三、内存占用与资源利用

  • 线程:由于线程的堆栈大小较大且固定,创建大量线程会占用大量内存资源,可能导致系统资源耗尽。
  • 协程:Go协程的内存占用较小,且可以动态调整堆栈大小,因此可以创建大量的goroutines而不会过分消耗内存。这使得Go语言在处理大量并发任务时能够保持高性能和低资源消耗。

四、并发模型与通信机制

  • 线程:线程通常使用共享内存的方式进行并发编程,需要开发者自己处理同步和互斥问题,容易出现竞态条件和死锁等问题。
  • 协程:Go协程使用基于通信的并发模型,即通过channel进行协程之间的通信和同步。这种模型更容易实现并发安全,避免了传统线程间共享数据的竞态条件问题。此外,Go协程之间通过channel进行通信,这也是一种高效的同步机制。

综上所述,Golang协程之所以比线程轻量,是由于其初始堆栈大小小、动态调整机制、M:N调度模型、低调度开销、小内存占用、高效的并发模型和通信机制等多方面因素共同作用的结果。这些特点使得Go语言在处理大量并发任务时能够保持高性能和低资源消耗。


http://www.kler.cn/a/459434.html

相关文章:

  • 《计算机网络A》单选题-复习题库解析-3
  • windows 图形基础架构简介
  • 框架模块说明 #09 日志模块_01
  • 非docker方式部署openwebui过程记录
  • 机场安全项目|基于改进 YOLOv8 的机场飞鸟实时目标检测方法
  • CentOS — 目录管理
  • o1到o3的发展历程
  • lombok-macros
  • 【Go】context标准库
  • 步进电机驱动算法——S形加减速算法原理
  • 面试经典150题——数组/字符串(二)
  • 开发运维基本功:无需复杂配置快速实现本地Nginx的公网远程访问
  • 【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(三)
  • 打破传统,手势验证码识别
  • DP协议:PHY层
  • JS - Array Api
  • 从零开始学架构——互联网架构的演进
  • C++ hashtable
  • No.3十六届蓝桥杯备战|数据类型长度|sizeof|typedef|练习(C++)
  • 线程-4-线程库与线程封装
  • 完整的 FFmpeg 命令使用教程
  • 【PyCharm】如何把本地整个项目同步到服务器?
  • 在web.xml中配置Servlet映射
  • 【Next.js】002-路由篇|App Router
  • 冒泡排序c语言
  • 百度PaddleSpeech识别大音频文件报错