最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中進程、協(xié)程與線程的區(qū)別詳解

 更新時間:2023年08月04日 11:30:56   作者:小魏的博客  
這篇文章主要介紹了Java中進程,線程,協(xié)程的概念、區(qū)別以及使用場景的選擇,早期的操作系統(tǒng)每個程序就是一個進程,知道一個程序運行完,才能進行下一個進程,就是"單進程時代",一切的程序只能串行發(fā)生,需要的朋友可以參考下

進程

我們知道,一切的軟件都是跑在操作系統(tǒng)上,真正用來干活 (計算) 的是 CPU。

早期的操作系統(tǒng)每個程序就是一個進程,知道一個程序運行完,才能進行下一個進程,就是 “單進程時代”。

一切的程序只能串行發(fā)生。

早期的單進程操作系統(tǒng),面臨 2 個問題:

  1. 單一的執(zhí)行流程,計算機只能一個任務一個任務處理。
  2. 進程阻塞所帶來的 CPU 時間浪費。

那么能不能有多個進程來一起來執(zhí)行多個任務呢?

后來操作系統(tǒng)就具有了最早的并發(fā)能力:多進程并發(fā),當一個進程阻塞的時候,切換到另外等待執(zhí)行的進程,這樣就能盡量把 CPU 利用起來,CPU 就不浪費了。

為了更合理的利用 CPU 資源,內(nèi)存劃分為多塊,不同進程使用各自的內(nèi)存空間互不干擾,CPU 可以在多個進程之間切換執(zhí)行,讓 CPU 的利用率變高。

為了實現(xiàn) CPU 在多個進程之間切換,需要保存進程的上下文(如程序計數(shù)器、棧等等),以便下次切換回來可以恢復執(zhí)行。

還需要一種調(diào)度算法,Linux 中采用了基于時間片和優(yōu)先級的完全公平調(diào)度算法。

 進程的上下文切換涉及到從【用戶態(tài)】->【內(nèi)核態(tài)】->【用戶態(tài)】的過程,并且上下文中包含非常多的數(shù)據(jù),如下圖所示:

在多進程 / 多線程的操作系統(tǒng)中,就解決了阻塞的問題,因為一個進程阻塞 cpu 可以立刻切換到其他進程中去執(zhí)行,而且調(diào)度 cpu 的算法可以保證在運行的進程都可以被分配到 cpu 的運行時間片。這樣從宏觀來看,似乎多個進程是在同時被運行。

但新的問題就又出現(xiàn)了,進程擁有太多的資源,進程的創(chuàng)建、切換、銷毀,都會占用很長的時間,CPU 雖然利用起來了,但如果進程過多,CPU 有很大的一部分都被用來進行進程調(diào)度了。

怎么才能提高 CPU 的利用率呢?

線程

1、介紹

多進程的出現(xiàn)是為了解決 CPU 利用率的問題,那為什么還需要線程?答案是為了減少上下文切換時的開銷。

進程在如下兩個時間點可能會讓出 CPU,進行 CPU 切換:

  • 進程阻塞,如網(wǎng)絡阻塞、代碼層面的阻塞(鎖、sleep等)、系統(tǒng)調(diào)用等
  • 進程時間片用完,讓出 CPU

而進程切換 CPU 時需要進行這兩步:

  1. 切換頁目錄以使用新的地址空間
  2. 切換內(nèi)核棧和硬件上下文

進程和線程在 Linux 中沒有本質(zhì)區(qū)別,他們最大的不同就是進程有自己獨立的內(nèi)存空間,而線程(同進程中)是共享內(nèi)存空間。

在進程切換時需要轉(zhuǎn)換內(nèi)存地址空間,而線程切換沒有這個動作,所以線程切換比進程切換代價更小。

為什么內(nèi)存地址空間轉(zhuǎn)換這么慢?

Linux 實現(xiàn)中,每個進程的地址空間都是虛擬的,虛擬地址空間轉(zhuǎn)換到物理地址空間需要查頁表,這個查詢是很慢的過程,因此會用一種叫做 TLB 的 cache 來加速,當進程切換后,TLB 也隨之失效了,所以會變慢。

綜上,線程是為了降低進程切換過程中的開銷。

2、線程切換

從單線程應用到多線程應用帶來的不僅僅是好處。也會帶來開銷。

當一個cpu從一個線程切換到另一個線程時,cpu需要保存當前線程的本地數(shù)據(jù),程序當前的指針等,然后加載下一個等待執(zhí)行的線程的本地數(shù)據(jù),程序指針等。這種切換被稱之為上下文切換。cpu從執(zhí)行一個線程切換去執(zhí)行另一個線程。

 線程的上下文切換涉及到從【用戶態(tài)】->【內(nèi)核態(tài)】->【用戶態(tài)】的過程,上下文中包含的數(shù)據(jù)雖然不像進程中的那么多,但整個過程也非常耗時,具體包含的數(shù)據(jù)如下圖所示:

協(xié)程

1、介紹

很明顯,CPU 調(diào)度切換的是進程和線程。盡管線程看起來很美好,但實際上多線程開發(fā)設計會變得更加復雜,要考慮很多同步競爭等問題,如鎖、競爭沖突等。

多進程、多線程已經(jīng)提高了系統(tǒng)的并發(fā)能力,但是在當今互聯(lián)網(wǎng)高并發(fā)場景下,為每個任務都創(chuàng)建一個線程是不現(xiàn)實的,因為會消耗大量的內(nèi)存 (進程虛擬內(nèi)存會占用 4GB [32 位操作系統(tǒng)],而線程也要大約 4MB)。

大量的進程 / 線程出現(xiàn)了新的問題

  • 系統(tǒng)線程會占用非常多的內(nèi)存空間
  • 過多的線程切換會占用大量的系統(tǒng)時間。
  • 多線程開發(fā)涉及鎖、競爭沖突等,開發(fā)復雜

當我們的程序是 IO 密集型時(如 web 服務器、網(wǎng)關等),為了追求高吞吐,有兩種思路:

  1. 為每個請求開一個線程處理,為了降低線程的創(chuàng)建開銷,可以使用線程池技術,理論上線程池越大,則吞吐越高,但線程池越大,CPU花在切換上的開銷也越大。
  2.  使用異步非阻塞的開發(fā)模型,用一個進程或線程接收請求,然后通過 IO 多路復用讓進程或線程不阻塞,省去上下文切換的開銷

這兩個方案,優(yōu)缺點都很明顯:方案1實現(xiàn)簡單,但性能不高;方案2性能非常好,但實現(xiàn)起來復雜。

2、解決方案

有沒有介于這兩者之間的方案?既要簡單,又要性能高,協(xié)程就解決了這個問題。

而協(xié)程剛好可以解決上述2個問題。

協(xié)程是用戶視角的一種抽象,操作系統(tǒng)并沒有協(xié)程的概念。

協(xié)程運行在線程之上,協(xié)程的主要思想是在用戶態(tài)實現(xiàn)調(diào)度算法,用少量線程完成大量任務的調(diào)度。

協(xié)程需要解決線程遇到的幾個問題:

  • 內(nèi)存占用要小,且創(chuàng)建開銷要小
    • 用戶態(tài)的協(xié)程,可以設計的很小,可以達到 KB 級別。是線程的千分之一。
    • 線程??臻g通常是MB級別, 協(xié)程??臻g最小KB級別。
  • 減少上下文切換的開銷
  • 讓可執(zhí)行的線程盡量少,這樣切換次數(shù)必然會少
    • 讓線程盡可能的處于運行狀態(tài),而不是阻塞讓出時間片
      • 多個協(xié)程多個協(xié)程綁定一個或者多個線程上
        • 當一個協(xié)程執(zhí)行完成后,可以選擇主動讓出,讓另一個協(xié)程運行在當前線程之上(分時復用)。
        • 即使有協(xié)程阻塞,該線程的其他協(xié)程也可以被 runtime 調(diào)度,轉(zhuǎn)移到其他可運行的線程上。
  • 降低開發(fā)難度
    • goroutine是golang中對協(xié)程的實現(xiàn)
    • goroutine底層實現(xiàn)了少量線程干多事,減少切換時間等
    • 程序員可以輕松創(chuàng)建協(xié)程,無需去關注底層性能優(yōu)化的細節(jié)

 相較進程和線程而言,協(xié)程的上下文切換則快了很多, 它只需在【用戶態(tài)】即可完成上下文的切換,并且需要切換的上下文信息也較少

進程、線程、協(xié)程上下文切換開銷

為什么 【用戶態(tài)】->【內(nèi)核態(tài)】->【用戶態(tài)】這一過程比較耗時,耗資源呢?

我們知道,操作系統(tǒng)保持跟蹤進程運行所需的所有狀態(tài)信息,這種狀態(tài),也就是上下文。

進程的上下文包括許多信息,比如PC和寄存器文件的當前值,以及主存的內(nèi)容。

在任何一個時刻,單處理器系統(tǒng)都只能執(zhí)行一個進程的代碼。當操作系統(tǒng)決定要把控制權從當前進程轉(zhuǎn)移到某個新進程時,就會進行上下文切換,即保存當前進程的上下文、恢復新進程的上下文,然后將控制權傳遞到新進程。新進程就會從它上次停止的地方開始。

假設現(xiàn)在有兩個并發(fā)的進程:shel進程和hello進程。最開始,只有 shell進程在運行,即等待命令行上的輸人。當我們讓它運行hello程序時, shell通過調(diào)用一個專門的函數(shù),即系統(tǒng)調(diào)用,來執(zhí)行我們的請求,系統(tǒng)調(diào)用會將控制權傳遞給操作系統(tǒng)。操作系統(tǒng)保存 shell進程的上下文,創(chuàng)建一個新的hello進程及其上下文,然后將控制權傳給新的hello進程。hello進程終止后,操作系統(tǒng)恢復shll進程的上下文,并將控制權傳回給它, shell進程會繼續(xù)等待下一個命令行輸入。

從上面這個實例我們可以得出結(jié)論:

(1)上一個進程的上下文信息還在內(nèi)存和處理器當中,我們要保存這些信息的話,就必須陷入到內(nèi)核態(tài)才可以。

(2)創(chuàng)建一個新的進程,以及它的上下文信息,并且將控制權交給這個新進程,這些都只有在內(nèi)核態(tài)才能實現(xiàn)。

綜上,我們可以得出結(jié)論,進程和線程的上下文切換相較于協(xié)程比較“耗時耗力”。

那么協(xié)程的上下文切換相較線程有哪些提升?

協(xié)程上下文切換只涉及CPU上下文切換,而所謂的CPU上下文切換是指少量寄存器(PC / SP / DX)的值修改,協(xié)程切換非常簡單,就是把當前協(xié)程的 CPU 寄存器狀態(tài)保存起來,然后將需要切換進來的協(xié)程的 CPU 寄存器狀態(tài)加載的 CPU 寄存器上就 ok 了。而對比線程的上下文切換則需要涉及模式切換(從用戶態(tài)切換到內(nèi)核態(tài))、以及 16 個寄存器、PC、SP…等寄存器的刷新;

線程??臻g通常是 2M, 協(xié)程棧空間最小 2K。

ChatGPT的回答

協(xié)程(Coroutine)和線程(Thread)都是常見的并發(fā)編程技術。線程是操作系統(tǒng)進行調(diào)度的最小單位,而協(xié)程則是在應用程序內(nèi)部進行調(diào)度的最小單位。在多線程并發(fā)編程中,線程之間的切換涉及到內(nèi)核態(tài)和用戶態(tài)之間的切換,會帶來一定的開銷。而在協(xié)程并發(fā)編程中,由于很多協(xié)程都運行在同一個線程內(nèi),因此協(xié)程之間的切換只涉及到用戶態(tài)之間的切換,避免了內(nèi)核態(tài)和用戶態(tài)之間的頻繁切換,從而提高了性能。

從底層角度來看,線程和協(xié)程之間的主要區(qū)別在于它們的調(diào)度方式和內(nèi)存模型。在線程模型中,每個線程都有自己的線程棧和寄存器狀態(tài),由操作系統(tǒng)進行調(diào)度。線程之間的切換需要保存和恢復線程棧和寄存器狀態(tài),這會帶來一定的開銷。而在協(xié)程模型中,多個協(xié)程共享同一個線程棧和寄存器狀態(tài),由協(xié)程庫進行調(diào)度。協(xié)程之間的切換只需要保存和恢復少量的狀態(tài)信息,避免了線程切換的大量開銷。

具體來說,在協(xié)程模型中,協(xié)程的狀態(tài)可以通過一個狀態(tài)機來表示。每個協(xié)程只有在遇到IO等需要等待的操作時才會主動讓出CPU,轉(zhuǎn)而讓其他協(xié)程繼續(xù)執(zhí)行。當IO操作完成后,該協(xié)程會被喚醒并從上次掛起的狀態(tài)恢復執(zhí)行。這種調(diào)度方式可以避免線程切換的開銷,并且允許多個協(xié)程在同一線程上進行并發(fā)執(zhí)行,從而提高了性能。

總之,協(xié)程的快速切換和共享內(nèi)存模型使得它在一些場景下比線程更加高效,但是也需要注意到協(xié)程并發(fā)編程可能存在一些潛在的問題,例如上下文切換和調(diào)度算法等方面的性能問題和錯誤處理等方面的編程難度問題。因此,在選擇編程模型時需要根據(jù)具體場景進行權衡和選擇。

總結(jié)

從單進程到多進程提高了 CPU 利用率;從進程到線程,降低了上下文切換的開銷;從線程到協(xié)程,進一步降低了上下文切換的開銷,使得高并發(fā)的服務可以使用簡單的代碼寫出來

協(xié)程(協(xié)同程序):同一時間只能執(zhí)行某個協(xié)程。開辟多個協(xié)程開銷不大。協(xié)程適合對某任務進行分時處理。

線程:同一時間可以同時執(zhí)行多個線程。開辟多條線程開銷很大。線程適合多任務同時處理。

協(xié)程可以讓同一個線程執(zhí)行多個協(xié)程任務。降低了線程切換的開銷。

雖然協(xié)程也切換,但是由于多個線程共享線程棧和寄存器,因此協(xié)程切換就不涉及到線程棧和寄存器的開銷了,僅有協(xié)程本身一些狀態(tài)的變更。

到此這篇關于Java中進程、協(xié)程與線程的區(qū)別詳解的文章就介紹到這了,更多相關Java進程、協(xié)程與線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • IntelliJ IDEA下自動生成Hibernate映射文件以及實體類

    IntelliJ IDEA下自動生成Hibernate映射文件以及實體類

    這篇文章主要介紹了IntelliJ IDEA下自動生成Hibernate映射文件以及實體類,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • JAVA實現(xiàn)簡單搶紅包算法(模擬真實搶紅包)

    JAVA實現(xiàn)簡單搶紅包算法(模擬真實搶紅包)

    這篇文章主要介紹了JAVA實現(xiàn)簡單搶紅包算法(模擬真實搶紅包)的實例代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • Java版給愛人表白的玫瑰花程序代碼

    Java版給愛人表白的玫瑰花程序代碼

    這篇文章主要講解了Java版給愛人表白的玫瑰花程序代碼,具有很好的參考價值,希望對大家有所幫助,一起跟隨小編過來看看吧
    2018-05-05
  • java多線程中的異常處理機制簡析

    java多線程中的異常處理機制簡析

    在java多線程程序中,所有線程都不允許拋出未捕獲的checked exception,也就是說各個線程需要自己把自己的checked exception處理掉,需要了解的朋友可以參考下
    2012-11-11
  • mybatis中嵌套使用foreach需要注意的坑

    mybatis中嵌套使用foreach需要注意的坑

    在使用MyBatis進行數(shù)據(jù)庫操作時,如果需要在一個大的foreach標簽中嵌套另一個foreach,需要注意內(nèi)層foreach的item屬性不能與外層重復,如果出現(xiàn)重復,會導致綁定參數(shù)時找不到正確的參數(shù),從而拋出異常
    2024-09-09
  • SpringBoot3實現(xiàn)Gzip壓縮優(yōu)化的技術指南

    SpringBoot3實現(xiàn)Gzip壓縮優(yōu)化的技術指南

    隨著 Web 應用的用戶量和數(shù)據(jù)量增加,網(wǎng)絡帶寬和頁面加載速度逐漸成為瓶頸,為了減少數(shù)據(jù)傳輸量,提高用戶體驗,我們可以使用 Gzip 壓縮 HTTP 響應,本文將介紹如何在 Spring Boot 3 中實現(xiàn) Gzip 壓縮優(yōu)化,需要的朋友可以參考下
    2025-04-04
  • Java導出Excel通用工具類實例代碼

    Java導出Excel通用工具類實例代碼

    這篇文章主要給大家介紹了關于Java導出Excel通用工具類的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • JavaBean實體類處理外鍵過程解析

    JavaBean實體類處理外鍵過程解析

    這篇文章主要介紹了JavaBean實體類處理外鍵過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • LoggingEventAsyncDisruptorAppender類執(zhí)行流程源碼解讀

    LoggingEventAsyncDisruptorAppender類執(zhí)行流程源碼解讀

    這篇文章主要介紹了LoggingEventAsyncDisruptorAppender類執(zhí)行流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 優(yōu)雅地在Java 8中處理異常的方法詳解

    優(yōu)雅地在Java 8中處理異常的方法詳解

    異常處理是我們在日常開發(fā)中經(jīng)常會遇到的一種需求,下面這篇文章主要給大家介紹了關于如何優(yōu)雅地在Java 8中處理異常的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們來一起看看吧
    2019-01-01

最新評論

开原市| 大足县| 津市市| 来宾市| 兴和县| 龙游县| 海南省| 富宁县| 治多县| 嘉义市| 久治县| 定西市| 长乐市| 金川县| 南康市| 酒泉市| 舟山市| 宝丰县| 崇左市| 搜索| 尼木县| 奉新县| 榆中县| 柳林县| 永定县| 红安县| 盐边县| 福州市| 黎川县| 秭归县| 明溪县| 怀集县| 南康市| 衡南县| 龙山县| 云霄县| 渭源县| 绥芬河市| 大竹县| 玛沁县| 秦安县|