协程切换为什么就要比线程低?

一、进程、线程、协程

进程是一个可执行程序在运行时的一块独立的虚拟内存空间,Linux 给每个进程分配一个虚拟内存空间,包括栈空间、未使用内存、堆空间、BSS、DATA、TEXT 等。

线程可以理解为轻量级进程,多个线程"寄生"在一个进程中,每个线程有独立的栈空间,其它虚拟内存空间,多个线程共享,所以线程之间通信比较简单,也就是说线程之间可以通过共享内存通信。

进程和线程都是 CPU 的一个执行单元,在内核态切换,切换成本较高。

协程是用户态的一个伪执行单元,在用户态切换执行流程,切换成本较低。

二、切换执行单元的成本

我们通过介绍线程和协程的切换流程,讲述为什么在内核态切换的成本较高,而在用户态切换的成本较低?

因为进程和线程都是内核态切换,并且进程切换成本比线程切换成本更高,所以只介绍线程切换和协程切换的切换成本。

内核态切换 - 线程

在了解线程在内核态切换之前,我们先了解一下什么是 CPU 时间片,在操作系统中,我们会安装很多软件,并且我们会同时使用多个软件,而 CPU 资源有限。

为了让多个软件可以在操作系统中同时运行,CPU 分成一个个的时间片,在每个时间片中运行一个软件的一个线程,因为时间片非常短,所以我们会感觉多个软件在同时运行。

在编写代码时,我们为了可以让程序被分配到更多的 CPU 资源,可以多创建一些线程,用于提升程序运行的效率。需要注意的是,线程并不是创建越多越好。

因为 CPU 在内核态切换执行单元(线程)时,会有时间成本,在进行切换执行单元时,需要保存寄存器中的数据,将原执行单元的状态保存,切换操作也会占用 CPU 资源(时间片),从而减少了供线程运行的 CPU 资源(时间片)。

除了时间成本之外,还会有性能开销,系统内核调度线程,需要用户空间和内核空间切换,因为只有拥有最高权限的内核空间才可以调度线程,限于篇幅,我们不再展开叙述。

用户态切换 - 协程

因为通过创建线程(执行单元),为程序争取更多的 CPU 资源,在线程切换时也会浪费 CPU 资源(时间成本),所以可以将执行单元不再在内核态运行,改为在用户态运行,也就是协程。

协程的切换成本较低,是因为切换比较简单,并且是在用户态进行切换,切换的时间成本较低(纳秒级),只需将当前协程的 CPU 寄存器的状态先保存起来,然后将需要 CPU 资源的协程的 CPU 寄存器的状态加载到 CPU 寄存器中。

关于 Go 协程的调度,我们在之前的文章中介绍过,此处不再赘述。

三、内存占用方面

除了 CPU 资源有限之外,内存资源也是有限的,所以我们还需要了解进程、线程、协程的内存占用。

读者朋友们应该知道 32 位操作系统只支持 4G 内存的内存条,这是因为进程在 32 位操作系统中最多只能占用 4G 内存,而在 64 位操作系统中可以占用更多内存。

线程占用内存一般是 10MB,不同的操作系统版本之间有些差异,区间在 4M - 64M。

协程占用内存最小,一个协程占用 2KB 左右的内存。

四、总结

本文我们主要介绍为什么 Go 协程比进程和线程占用的系统资源低,通过进程、线程、协程的 CPU 资源和内存占用的比较,发现无论是在切换时消耗的 CPU 资源(时间片),还是内存占用,Go 协程都有明显优势。

一句话总结就是 Go 协程的切换成本和内存占用比线程和进程都低。

需要注意的是,Go 协程占用系统资源低,并不代表可以无限创建 Go 协程。

相关推荐
Ysjt | 深16 分钟前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
凌冰_18 分钟前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
ephemerals__22 分钟前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
码农飞飞26 分钟前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货28 分钟前
Rust 的简介
开发语言·后端·rust
湫ccc35 分钟前
《Python基础》之基本数据类型
开发语言·python
Matlab精灵36 分钟前
Matlab函数中的隐马尔可夫模型
开发语言·matlab·统计学习
Microsoft Word37 分钟前
c++基础语法
开发语言·c++·算法
数据小爬虫@39 分钟前
如何利用java爬虫获得淘宝商品评论
java·开发语言·爬虫
qq_172805591 小时前
RUST学习教程-安装教程
开发语言·学习·rust·安装