併發編程專題(一)-併發與多線程

1.併發

1.1 併發與並行

首先介紹一下併發與並行,兩者雖然只有一字之差,但實際上卻有着本質的區別,其概念如下:

  • 並行性(parallel):指在同一時刻,有多條指令在多個處理器上同時執行;
  • 併發性(concurrency):指在同一時刻只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。

併發編程專題(一)-併發與多線程

在操作系統中,安裝了多個程序,併發指的是在一段時間內宏觀上有多個程序同時運行,這在單 CPU 系統中,每一時刻只能有一道程序執行,即微觀上這些程序是分時的交替運行,只不過是給人的感覺是同時運行,那是因爲分時交替運行的時間是非常短的。

而在多個 CPU 系統中,則這些可以併發執行的程序便可以分配到多個處理器上(CPU),實現多任務並行執行,即利用每個處理器來處理一個可以併發執行的程序,這樣多個程序便可以同時執行。目前電腦市場上說的多核 CPU,便是多核處理器,核越多,並行處理的程序越多,能大大的提高電腦運行的效率。
併發編程專題(一)-併發與多線程

注意:單核處理器的計算機肯定是不能並行的處理多個任務的,只能是多個任務在單個CPU上併發運行。同理,線程也是一樣的,從宏觀角度上理解線程是並行運行的,但是從微觀角度上分析卻是串行運行的,即一個線程一個線程的去運行,當系統只有一個CPU時,線程會以某種順序執行多個線程,我們把這種情況稱之爲線程調度。

1.2 順序編程與併發編程

我們在解決編程問題時,通常使用順序編程來解決,即程序中的所有事物在任意時刻都只能執行一個步驟。然而對於某些問題,我們希望能夠並行地執行程序中的多個部分,來達到我們想要的效果。在單處理器機器中,我們可以將程序劃分爲多個部分,然後每個部分由該處理器併發執行。在多處理器機器中,我們可以將程序劃分多個部分,然後每個部分分別在多個處理器上並行執行。當然爲了更加充分利用CPU資源,我們也可以在多個處理器上併發執行,那麼在這我們就涉及到了另一種編程模式了併發編程。併發編程又叫多線程編程。併發編程使我們可以將程序劃分爲多個分離的、獨立運行的任務。通過使用多線程機制,每個獨立任務都將由線程來驅動。一個線程就是在進程中的一個單一的順序控制流,單個進程可以擁有多個"併發執行"的任務。這樣使程序的每個任務,都好像擁有一個自己的CPU一樣。但其底層機制還是是切分CPU時間,CPU都有個時鐘頻率,表示每秒中能執行CPU指令的次數。在每個時鐘週期內,CPU實際上只能去執行一條也有可能多條指令。操作系統將進程進行管理,輪流分配每個進程很短的一段是時間但不一定是均分,然後在每個進程內部,程序代碼自己處理該進程內部線程的時間分配,多個線程之間相互的切換去執行,這個切換時間也是非常短的所以通常我們不需要考慮它。

併發是指"發",不是處理,最常見的情況就是許多人在一小段時間內都點擊了你的網站,發出了處理請求。併發編程是對併發狀況的應對,在單處理器和多處理器機器上都可對其進行應對,可這個處理方案和架構以及算法有關。CPU一般是分時的,會在極短的時間內不停地切換給不同的線程使用,無論多少併發都會處理下去,只是時間問題,如何提高處理效率就看採用的技術了。

1.3 併發編程的優勢

如果使用得當,線程可以有效地降低程序的開發和維護等成本,同時提升複雜應用程序的性能。具體說,線程的優勢有:

  • 發揮多處理器的強大能力
    現在,多處理器系統正日益盛行,並且價格不斷降低,即時在低端服務器和中斷桌面系統中,通常也會採用多個處理器,這種趨勢還在進一步加快,因爲通過提高時鐘頻率來提升性能已變得越來越困難,處理器生產廠商都開始轉而在單個芯片上放置多個處理器核。試想,如果只有單個線程,雙核處理器系統上程序只能使用一半的CPU資源,擁有100個處理器的系統上將有99%的資源無法使用。多線程程序則可以同時在多個處理器上執行,如果設計正確,多線程程序可以通過提高處理器資源的利用率來提升系統吞吐率。

    • 在單處理器系統上獲得更高的吞吐率
      如果程序是單線程的,那麼當程序等待某個同步I/O操作完成時,處理器將處於空閒狀態。而在多線程程序中,如果一個線程在等待I/O操作完成,另一個線程可以繼續運行,使得程序能在I/O阻塞期間繼續運行。

    • 建模的簡單性
      通過使用線程,可以將複雜並且異步的工作流進一步分解爲一組簡單並且同步的工作流,每個工作流在一個單獨的線程中運行,並在特定的同步位置進行交互。我們可以通過一些現有框架來實現上述目標,例如Servlet和RMI,框架負責解決一些細節問題,例如請求管理、線程創建、負載平衡,並在正確的時候將請求分發給正確的應用程序組件。編寫Servlet的開發人員不需要了解多少請求在同一時刻要被處理,也不需要了解套接字的輸入流或輸出流是否被阻塞,當調用Servlet的service方法來響應Web請求時,可以以同步的方式來處理這個請求,就好像它是一個單線程程序。

    • 異步事件的簡化處理
      服務器應用程序在接受多個來自遠程客戶端的套接字連接請求時,如果爲每個連接都分配其各自的線程並且使用同步I/O,那麼就會降低這類程序的開發難度。如果某個應用程序對套接字執行讀操作而此時還沒有數據到來,那麼這個讀操作將一直阻塞,直到有數據到達。在單線程應用程序中,這不僅意味着在處理請求的過程中將停頓,而且還意味着在這個線程被阻塞期間,對所有請求的處理都將停頓。爲了避免這個問題,單線程服務器應用程序必須使用非阻塞I/O,但是這種I/O的複雜性要遠遠高於同步I/O,並且很容易出錯。然而,如果每個請求都擁有自己的處理線程,那麼在處理某個請求時發生的阻塞將不會影響其他請求的處理。

      在實際應用中,多線程是非常有用的,一個瀏覽器必須能同時下載多個圖片;一個Web服務器必須能同時響應多個用戶請求;Java虛擬機本身就在後臺提供了一個超級線程來進行垃圾回收;圖形用戶界面(GUI)應用也需要啓動單獨的線程從主機環境收集用戶界面事件……總之,多線程在實際編程中的應用是非常廣泛的。

2.進程和線程

  • 進程:是指一個內存中運行的應用程序,每個進程都有一個獨立的內存空間,一個應用程序可以同時運行多個進程;進程也是程序的一次執行過程,是系統運行程序的基本單位;系統運行一個程序即是一個進程從創建、運行到消亡的過程。進程可以理解爲受操作系統管理的基本運行單元。360瀏覽器是一個進程、WPS也是一個進程,正在操作系統中運行的".exe"都可以理解爲一個進程。

併發編程專題(一)-併發與多線程

  • 線程:線程是進程中的一個執行單元,負責當前進程中程序的執行,一個進程中至少有一個線程。一個進程中是可以有多個線程的,這個應用程序也可以稱之爲多線程程序。
    進程中獨立運行的子任務就是一個線程。像QQ.exe運行的時候就有很多子任務在運行,比如聊天線程、好友視頻線程、下載文件線程等等。
    併發編程專題(一)-併發與多線程
    簡而言之:一個程序運行後至少有一個進程,一個進程中可以包含多個線程。

    3.多任務、多進程、多線程

    幾乎所有的操作系統都支持同時運行多個任務,一個任務通常就是一個程序,每個運行中的程序就是一個進程。當一個程序運行時,內部可能包含了多個順序執行流,每個順序執行流就是一個線程

    3.1 多進程

    實現併發最直接的方式是在操作系統級別使用進程,進程是運行在它自己的地址空間內的自包容的程序。多任務操作系統可以通過週期性地將CPU從一個進程切換到另一個進程,來實現同時運行多個進程。 儘管對於一個CPU而言,它在某個時間點只能運行一個進程,但CPU可以在多個進程之間進行輪換執行,並且CPU的切換速度極高,使我們無法感知其切換的過程,就好像有多個進程在同時執行。
    幾乎所有的操作系統都支持進程的概念,所有運行中的任務通常對應一個進程(Process)。當一個程序進入內存運行時,即變成一個進程。進程是處於運行過程中的程序,並且具有一定的獨立功能,進程是系統進行資源分配和調度的一個獨立單位。一般而言,進程包含如下3個特徵。

獨立性:進程是系統中獨立存在的實體,它可以擁有自己獨立的資源,每一個進程都擁有自己私有的地址空間。在沒有經過進程本身允許的情況下,一個用戶進程不可以直接訪問其他進程的地址空間。
動態性:進程與程序的區別在於,程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合。在進程中加入了時間的概念,進程具有自己的生命週期和各種不同的狀態,這些概念在程序中部是不具備的。
併發性:多個進程可以在單個處理器上併發執行,多個進程之間不會互相影響。

3.2 多線程
3.2.1 多線程概述

多線程則擴展了多進程的概念。使得同一個進程中也可以同時併發處理多個任務。線程(Thread)也被稱作輕量級進程(Lightweight Process)。線程是進程的執行單元,就像進程在操作系統中的地位一樣,線程在程序中是獨立的、併發的執行流。當進程被初始化後,主線程就被創建了。對於絕大多數的應用程序來說,通常僅要求有一個主線程,但也可以在該進程內創建多條順序執行流,這些順序執行流就是線程,每個線程也是互相獨立的。

線程是進程的組成部分,一個進程可以擁有多個線程,一個線程必須有一個父進程。線程可以擁有自己的堆棧、自己的程序計數器和自己的局部變量,但不擁有系統資源,它與父進程的其他線程共享該進程所擁有的全部資源。因爲多個線程共享父進程裏的全部資源,因此編程更加方便;但必須更加小心,我們必須確保線程不會妨礙同一進程裏的其他線程。

3.2.2 多線程機制

線程模型爲編程帶來了便利,它簡化了在單一程序中同時交織在一起的多個操作的處理。在使用線程時,CPU將輪流給每個任務分配其佔用時間。每個任務都覺得自己在一直佔用CPU,但事實上CPU時間是劃分成片段分配給了所有的任務。線程的一大好處是可以使你從這個層次抽身出來,即代碼不必知道它是運行在具有一個還是多個CPU的機器上。所以,使用線程機制是一種建立透明的、可擴展的程序的方法,如果程序行得太慢,爲機器增添一個CPU就能很容易地加快程序的運行速度。多任務和多線程往往是使用多處理器系統的最合理方式。

3.2.3 多線程調度

線程可以完成一定的任務,可以與其他線程共享父進程中的共享變量及部分環境,相互之間協同來完成進程所要完成的任務。線程是獨立運行的,它並不知道進程中是否還有其他線程存在,線程的執行是搶佔式的,也就是說,當前運行的線程在任何時候都可能被掛起,以便另外一個線程可以運行。

一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以併發執行。從邏輯角度來看,多線程存在於一個應用程序中,讓一個應用程序中可以有多個執行部分同時執行,但操作系統無須將多個線程看作多個獨立的應用,對多線程實現調度和管理以及資源分配。線程的調度和管理由進程本身負責完成。

納起採可以這樣說:操作系統可以同時執行多個任務,每個任務就是進程;進程可以同時執行多個任務,每個任務就是線程。簡而言之,一個程序運行後至少有一個進程,一個進程裏可以包含多個線程,但至少要包含一個線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章