網站首頁 編程語言 正文
一、進程與線程
進程是操作系統資源分配的基本單位,是程序運行的實例。例如打開一個瀏覽器就開啟了一個進程。
線程是操作系統調度到CPU中執行的基本單位。例如在瀏覽器里新建一個窗口就需要一個線程來進行處理。
在一般情況下,線程是進程的組成部分,一個進程可以包含多個線程。例如瀏覽器可以新建多個窗口。
進程中的多個線程并發執行并共享進程的內存等資源。例如多個窗口之間可以共享登錄狀態、cookie等信息。
進程之間相對獨立,不同進程具有不同的內存地址空間,系統資源描述符等。例如再新開一個瀏覽器,就又開啟了一個進程,瀏覽器之間狀態相互獨立。
開啟一個進程的開銷比開啟一個線程大得多,且進程具有獨立的內存空間,多進程之間的通信通常比較困難。
二、并發與并行
并發不等于并行。
并發并不意味著同一時刻所有任務都在執行,而是在一個時間段內,所有的任務都能執行完畢。例如在單核CPU上運行多線程程序,多線程會交替搶占CPU時間片,任意一個時刻只能執行一個具體的線程。
在多核CPU上,線程可以分布在多個CPU核心上運行,實現真正的并行處理。
在多核處理場景中,并發與并行往往同時存在,多核心在并行處理多個線程,單核心中的多個線程又在交替執行。
三、go協程與線程
線程是系統調度的基本單位。go協程由go語言運行時的調度器進行調度,操作系統內核感知不到協程的存在。
在多核處理場景中,線程是并發與并行同時存在的,而go協程依托于線程,因此多核處理場景下,go協程也是并發與并行同時存在的。因為go協程從屬于某一個線程,所以即便在單核處理器上某一時刻運行一個線程,在線程內go語言調度器也會切換多個協程執行,這時協程是并發的。在多核心處理器上,如果多個協程被分配給了不同的線程,而這些線程同時被不同的CPU核心所處理,這時協程就是并行處理的。
go協程與線程存在著很多不同之處:
1.調度方式
線程: 線程是根據CPU時間片進行搶占式調度的。操作系統通過中斷信號(定時器中斷、I/O設備中斷等)執行線程的上下文切換。當發生線程上下文切換時,需要從操作系統用戶態轉移到內核態,并保存狀態信息;當切換到下一個要執行的線程時,需要加載狀態信息并從內核態轉移到操作系統用戶態。
協程: 協程存在于用戶態,由go語言運行時調度器進行調度。協程從屬于某一個線程,多個協程可以調度到一個線程中,一個協程也可能切換到多個線程中執行,因此協程與線程是多對多(M:N
)的關系。
2.調度策略
- 線程:?搶占式調度。操作系統調度器為了均衡每個線程的執行周期,會定時發出中斷信號強制執行線程上下文切換。
- 協程:?協作式調度。一個協程處理完自己的任務后,可以主動將執行權限讓渡給其他協程,不會被輕易搶占。只有在協程運行了過長時間后,go語言調度器才會強制搶占其執行。
3.上下文切換速度
線程: 線程上下文的切換需要經過操作系統用戶態與內核態的切換,切換速度大約為1~2微秒。
協程: 協程屬于用戶態輕量級的線程,協程的切換不需要經過用戶態與內核態的切換,且切換時只需要保存極少的狀態值,因此切換速度快數倍,大約為0.2微秒左右。(大約10倍于線程的切換速度)
4.棧的大小
線程: 線程的棧大小一般是在創建時指定的,linux及mac上默認的棧大小一般為8MB(可以通過ulimit -s
查看)。2000個線程需要消耗16G虛擬內存。
協程: go協程棧大小默認為2KB, 16G虛擬內存可以創建800多萬個協程。在實踐中,經常可以看到存在成千上萬的協程。
四、GMP模型
協程(G)線程(M)邏輯處理器(P)模型描述了線程與協程的關系。在GMP模型中:
G
代表go協程(Goroutine
),M
代表實際的線程,P
代表邏輯處理器(Process
)。go語言為了方便協程的調度與緩存,抽象出了邏輯處理器P
。
在任一時刻,一個邏輯處理器P可能在本地包含多個協程G,同時綁定一個線程M。需要注意的是,一個協程G并不是固定綁定同一個邏輯處理器P的,可能轉移到其他邏輯處理器中。
邏輯處理器P對應的線程M也是不固定的,在某些時候可能轉移到其他P中執行。
原文鏈接:https://juejin.cn/post/7109899785322102820
相關推薦
- 2022-05-21 C#中Thread(線程)和Task(任務)實例詳解_C#教程
- 2022-07-11 Verilog中$display和$write任務以及格式化輸出
- 2022-05-26 詳解redis腳本命令執行問題(redis.call)_Redis
- 2022-04-17 C# 利用ExcelDataReader 讀取excel文件
- 2021-12-09 Linux環境下安裝JDK1.8_Linux
- 2022-05-20 關于Mybatis-plus中PaginationInterceptor分頁攔截器過時問題解決辦法
- 2022-09-13 Oracle使用fy_recover_data恢復truncate刪除的數據_oracle
- 2022-04-07 C++中類的默認成員函數詳解_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支