進程是程式執行的一個實例,擔當分配系統資源的實體,實程創建必須分配一個完整的獨立地址空間。它是操作系統動態執行的基本單元。
每個進程都有自己的記憶體空間,包含原始碼區域、數據區域、堆棧。進程是線性的容器,本身並不會運行,線程不能單獨存在,必須依賴進程。
一個程式至少有一個進程,一個進程至少有一個線程。
對於操作系統來說,一個任務就是一個進程,比如開一個瀏覽器就是啟動一個瀏覽器進程,打開一個app就是啟動一個app進程。一個進程不代表只有一個功能,例如在一個通訊app裡,其中擁有有打字通訊、語音通訊和傳檔案等許多功能。
線程是進程裡的執行者,一個進程中至少有一個線程。多線程是為了在單個程式中同時運行多個線程完成不同的任務或工作,不是為了提高運行效率,而是為了提高資源使用效率,進而提昇系統的效率。
線程是程序執行流的最小單元。一個標準的線程由當前的線程ID、當前指令指針、寄存器和堆棧組成。同一個進程中的多個線程之間可以並發執行。
我們有兩個選擇:
多個進程之間並不會共享資源,所以多進程會比多線程還需要更多的系統資源。多進程的好程是,假使其中一個進程發生錯誤被系統終止,其餘的進程也不會受到任何影響。
協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制(進程和線程都是由cpu 內核進行調度)。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢覆先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。
對於 進程、線程,都是有內核進行調度,有 CPU 時間片的概念,進行 搶占式調度(有多種調度算法)
對於 協程(用戶級線程),這是對內核透明的,也就是系統並不知道有協程的存在,是完全由用戶自己的程序進行調度的,因為是由用戶程序自己控制,那麽就很難像搶占式調度那樣做到強制的 CPU 控制權切換到其他進程/線程,通常只能進行 協作式調度,需要協程自己主動把控制權轉讓出去之後,其他協程才能被執行到。
協程有助於實現:
普遍認為 goroutine 是Go語言對於協程的實現。 不同的是,Golang 在 runtime、系統調用等多方面對 goroutine 調度進行了封裝和處理,當遇到長時間執行或者進行系統調用時,會主動把當前 goroutine 的CPU (P) 轉讓出去,讓其他 goroutine 能被調度並執行,也就是 Golang 從語言層面支持了協程。Golang 的一大特色就是從語言層面原生支持協程,在函數或者方法前面加 go關鍵字就可創建一個協程。
每個 goroutine (協程) 默認占用記憶體遠比 Java 、C 的線程少。
goroutine:2KB(官方)
線程:8MB(參考網絡)
線程/goroutine 切換開銷方面,goroutine 遠比線程小
線程:涉及模式切換(從用戶態切換到內核態)、16個寄存器、PC、SP...等寄存器的刷新等。
goroutine:只有三個寄存器的值修改 - PC / SP / DX.