官术网_书友最值得收藏!

1.3 線程的前世今生

線程是操作系統能夠進行運算和調度的最小單元,在一個進程中可以創建多個線程,每個線程可以并行執行多個任務,并行執行的線程數量是由CPU的核心數量決定的。

1.3.1 大白話理解進程和線程

可能大家對這句話的理解還比較抽象,筆者將從進程到線程的整個過程做一個簡單的分析。

我們平時使用Java語言寫出來的程序是由一系列.java結尾的文件組成的,這些文件是存儲在硬盤上的靜態文件,通過Java虛擬機編譯成和平臺無關的字節碼,也就是變成了.class結尾的文件。

當我們通過main()方法運行這個程序后,這些.class文件會被加載到內存中等待被執行,接著CPU開始執行這些程序的每一行指令,然后基于這些指令產生相應的結果,我們把這個運行中的程序稱為進程。

假設在這個程序中,有一段邏輯是從磁盤上解析一個文件進行持久化操作,當CPU執行到從磁盤讀取數據這個指令時,由于磁盤的I/O速度相比CPU的運算速度來說要慢很多,所以CPU在等待磁盤I/O返回的過程中一直處于閑置狀態。CPU作為計算機的核心資源,被閑置顯然是不合理的。

分時系統的出現解決了這個問題,分時系統是計算機對資源的一種共享方式,它利用多道程序和CPU時間片調度的方式使得多個用戶可以同時使用一臺計算機。

什么是多道程序呢?由于單個程序無法讓CPU和I/O設備始終處于忙碌狀態,所以操作系統允許同時加載多個程序到內存,也就是說可以同時啟動多個進程,系統給這些進程分配獨立的地址空間,以保證每個進程的地址不會相互干擾。

當CPU在執行某個進程中的指令出現I/O或其他阻塞時,為了提高CPU的利用率,操作系統會采用CPU調度算法把閑置的CPU時間片分配給第二個進程,當前進程運行結束后又會把CPU時間片分配給之前阻塞的進程來執行,從而保證CPU一直處于忙碌狀態,整個調度過程如圖1-1所示。

圖1-1 CPU時間片的切換

在多核CPU架構中運行多個進程,從而實現多個進程的并行執行,一切看起來很美好,那么為什么又要有線程這種設計呢?

原因是進程本身是一個比較重的設計。首先,每個進程需要有自己的地址空間,并且每次涉及進程切換時,需要保存當前CPU指令的上下文,這使得資源的消耗及性能的損耗比較大。其次,對一個獨立的進程來說,該進程內同一時刻只能做一件事,如果在這個進程中想實現同時執行多個任務并行執行,很顯然是做不到的。最重要的是,當進程中某個代碼出現阻塞時,會導致整個進程掛起,即便有些邏輯不依賴于該阻塞的任務也會無法執行。為了解決這個問題,人們把進程的資源分配和進程中任務調度的執行分開處理,因此形成了線程的概念。

引入線程的設計后,CPU的最小調度和分配單元就變成了線程,在一個進程中可以創建多個線程。因此,當出現上面描述的情況,即一個進程中存在多個任務時,我們可以針對每個任務分配獨立的線程來執行,當其中一個任務因為阻塞無法執行時,其他任務不會受到影響。

除此之外,線程的好處還有很多。

? 由于線程不需要分配操作系統資源,所以它相對進程來說是比較輕的。

? 線程的切換只需要保存少量的寄存器內容,相比進程來說,資源耗費更小,因此效率更高。

? 一個進程中可以創建多個線程,同一個進程中多個線程的CPU時間片的切換并不會導致進程切換,而且還能實現單進程中多個任務的并行執行。

總結一下,進程和線程的主要區別是,操作系統的資源管理方式不同,進程有獨立的地址空間,當一個進程崩潰后,不會影響其他進程。而線程是一個進程中不同的執行路徑,它有自己的堆棧和局部變量,但是沒有單獨的地址空間。

1.3.2 線程的核心價值

在影響服務端的并發數中有兩個指標是CPU核心數和應用中的線程數,它們是如何影響整體并發的呢?

我們知道,同一時刻能夠同時運行多少個線程是由CPU的核心數來決定的,對同一個任務來說,單線程的執行和多線程同時執行相比,多線程同時執行的效率更高,這就意味著從用戶發起請求到收到服務端的返回結果的耗時會大大縮短。這樣,一方面能夠提升用戶的響應速度,另一方面能夠快速釋放資源,使得整體架構的并發性能得到一定的提高。

如圖1-2所示,假設在一個用戶注冊的流程中,會涉及保存用戶信息到數據庫,以及發送注冊成功的郵件通知,前者需要耗時3秒才能執行完成,后者需要耗時2秒,那么整個流程執行完成并返回結果給用戶一共需要5秒,顯然這個時間相對來說是比較長的。

圖1-2 用戶注冊

如圖1-3所示,我們使用線程優化了圖1-2中的注冊流程,當用戶信息保存到數據庫之后,直接返回給用戶一個注冊成功的結果,由于發送郵件這個流程和注冊沒有直接的關聯性,所以可以采用異步線程來執行郵件發送。使用線程優化后,用戶就可以在3秒內收到注冊成功的通知。

圖1-3 使用線程優化后的注冊流程

上述這個案例,就利用了線程異步執行的特性。所謂異步,就是調用者發送一個任務執行指令后,不需要等待該指令的返回結果,而是可以繼續執行后續的流程。這種異步特性本質上說也是一種并行處理方式,就是在一個進程中可以同時處理多個任務。

1.3.3 如何理解并發和并行

從操作系統層面來說,并發和并行可以表示CPU執行多個任務的方式。

? 并發:并發是指兩個或多個任務在同一時間間隔內發生,比如在4核CPU上運行100個線程,由于核數限制,這100個線程無法在同一時刻運行,所以CPU只能采用時間片切換的方式來運行,如果這100個線程能夠在1s內全部處理完成,那么我們可以認為當前的并發數是100。

? 并行:當有多個CPU核心時,在同一個時刻可以同時運行多個任務,這種方式叫并行。比如,4核CPU可以同時運行4個線程。

從宏觀層面來說,一個系統能夠處理的請求數即當前系統的并發數,但是這個并發數是由很多因素決定的,其中最主要的因素就是當前進程最多允許同時打開的連接數,在Linux系統中可以通過命令ulimit -n查看,假如得到的結果是1024,那么該進程能夠并行處理的連接數就是1024。

總的來說,并行和并發的區別就是,多個人做多件事情和一個人做多件事情的區別。

主站蜘蛛池模板: 浦东新区| 布拖县| 唐山市| 富蕴县| 望奎县| 佛冈县| 民乐县| 育儿| 商水县| 河池市| 榆中县| 剑川县| 米林县| 弥勒县| 洱源县| 乃东县| 师宗县| 建阳市| 林口县| 越西县| 喀喇| 同心县| 驻马店市| 台北市| 双峰县| 宁海县| 平罗县| 常熟市| 象州县| 墨江| 宁波市| 临清市| 外汇| 黄浦区| 惠东县| 高青县| 色达县| 岑巩县| 岚皋县| 库尔勒市| 桦甸市|