1. 程式人生 > >python網路程式設計之執行緒

python網路程式設計之執行緒

 

一 .背景知識

1.程序

   之前我們已經瞭解了作業系統中程序的概念,程式並不能單獨執行,只有將程式裝載到記憶體中,系統為它分配資源才能執行,而這種執行的程式就稱之為程序。程式和程序的區別就在於:程式是指令的集合,它是程序執行的靜態描述文字;程序是程式的一次執行活動,屬於動態概念。在多道程式設計中,我們允許多個程式同時載入到記憶體中,在作業系統的排程下,可以實現併發地執行。這是這樣的設計,大大提高了CPU的利用率。程序的出現讓每個使用者感覺到自己獨享CPU,因此,程序就是為了在CPU上實現多道程式設計而提出的。

2.有了程序為什麼還要執行緒

程序有很多優點,它提供了多道程式設計,讓我們感覺我們每個人都擁有自己的CPU和其他資源,可以提高計算機的利用率。很多人就不理解了,既然程序這麼優秀,為什麼還要執行緒呢?其實,仔細觀察就會發現程序還是有很多缺陷的,主要體現在兩點上:

    • 程序只能在一個時間幹一件事,如果想同時幹兩件事或多件事,程序就無能為力了。

    • 程序在執行的過程中如果阻塞,例如等待輸入,整個程序就會掛起,即使程序中有些工作不依賴於輸入的資料,也將無法執行。

    如果這兩個缺點理解比較困難的話,舉個現實的例子也許你就清楚了:如果把我們上課的過程看成一個程序的話,那麼我們要做的是耳朵聽老師講課,手上還要記筆記,腦子還要思考問題,這樣才能高效的完成聽課的任務。而如果只提供程序這個機制的話,上面這三件事將不能同時執行,同一時間只能做一件事,聽的時候就不能記筆記,也不能用腦子思考,這是其一;如果老師在黑板上寫演算過程,我們開始記筆記,而老師突然有一步推不下去了,阻塞住了,他在那邊思考著,而我們呢,也不能幹其他事,即使你想趁此時思考一下剛才沒聽懂的一個問題都不行,這是其二。

  現在你應該明白了程序的缺陷了,而解決的辦法很簡單,我們完全可以讓聽、寫、思三個獨立的過程,並行起來,這樣很明顯可以提高聽課的效率。而實際的作業系統中,也同樣引入了這種類似的機制——執行緒。

3.執行緒的出現

    60年代,在OS中能擁有資源和獨立執行的基本單位是程序,然而隨著計算機技術的發展,程序出現了很多弊端,一是由於程序是資源擁有者,建立、撤消與切換存在較大的時空開銷,因此需要引入 輕型程序;二是由於對稱多處理機(SMP)出現, 可以滿足多個執行單位,而多個程序並行開銷過大。       因此在80年代,出現了 能獨立執行的基本單位——執行緒(Threads)
      注意:程序是資源分配的最小單位,執行緒是CPU排程的最小單位.        每一個程序中至少有一個執行緒。 

    在傳統作業系統中,每個程序有一個地址空間,而且預設就有一個控制執行緒

    執行緒顧名思義,就是一條流水線工作的過程,一條流水線必須屬於一個車間,一個車間的工作過程是一個程序

    車間負責把資源整合到一起,是一個資源單位,而一個車間內至少有一個流水線

    流水線的工作需要電源,電源就相當於cpu

    所以,程序只是用來把資源集中到一起(程序只是一個資源單位,或者說資源集合),而執行緒才是cpu上的執行單位。

    多執行緒(即多個控制執行緒)的概念是,在一個程序中存在多個控制執行緒,多個控制執行緒共享該程序的地址空間,相當於一個車間內有多條流水線,都共用一個車間的資源。

二 程序和執行緒的關係

 

    執行緒與程序的區別可以歸納為以下4點:       1)地址空間和其它資源(如開啟檔案):程序間相互獨立,同一程序的各執行緒間共享。某程序內的執行緒在其它程序不可見。       2)通訊:程序間通訊IPC,執行緒間可以直接讀寫程序資料段(如全域性變數)來進行通訊——需要程序同步和互斥手段的輔助,以保證資料的一致性。(就類似程序中的鎖的作用)       3)排程和切換:執行緒上下文切換比程序上下文切換要快得多。       4)在多執行緒作業系統中(現在咱們用的系統基本都是多執行緒的作業系統),程序不是一個可執行的實體,真正去執行程式的不是程序,是執行緒,你可以理解程序就是一個執行緒的容器。

 

三 執行緒的特點

在多執行緒的作業系統中,通常是在一個程序中包括多個執行緒,每個執行緒都是作為利用CPU的基本單位,是花費最小開銷的實體。執行緒具有以下屬性。

   1)輕型實體     執行緒中的實體基本上不擁有系統資源,只是有一些必不可少的、能保證獨立執行的資源。     執行緒的實體包括程式、資料和TCB。執行緒是動態概念,它的動態特性由執行緒控制塊TCB(Thread Control Block)描述。
    TCB包括以下資訊:
    (1)執行緒狀態。
    (2)當執行緒不執行時,被儲存的現場資源。
    (3)一組執行堆疊。
    (4)存放每個執行緒的區域性變數主存區。
    (5)訪問同一個程序中的主存和其它資源。
      用於指示被執行指令序列的程式計數器、保留區域性變數、少數狀態引數和返回地址等的一組暫存器和堆疊。
   2)獨立排程和分派的基本單位。     在多執行緒OS中,執行緒是能獨立執行的基本單位,因而也是獨立排程和分派的基本單位。由於執行緒很“輕”,故執行緒的切換非常迅速且開銷小(在同一程序中的)。   3)共享程序資源。     執行緒在同一程序中的各個執行緒,都可以共享該程序所擁有的資源,這首先表現在:所有執行緒都具有相同的程序id,這意味著,執行緒可以訪問該程序的每一個記憶體資源;此外,還可以訪問程序所擁有的已開啟檔案、定時器、訊號量機構等。由於同一個程序內的執行緒共享記憶體和檔案,所以執行緒之間互相通訊不必呼叫核心。   4)可併發執行。     在一個程序中的多個執行緒之間,可以併發執行,甚至允許在一個程序中所有執行緒都能併發執行;同樣,不同程序中的執行緒也能併發執行,充分利用和發揮了處理機與外圍裝置並行工作的能力。  

四 執行緒的實際應用場景

 

 

  開啟一個字處理軟體程序,該程序肯定需要辦不止一件事情,比如監聽鍵盤輸入,處理文字,定時自動將文字儲存到硬碟,這三個任務操作的都是同一塊資料,因而不能用多程序。只能在一個程序裡併發地開啟三個執行緒,如果是單執行緒,那就只能是,鍵盤輸入時,不能處理文字和自動儲存,自動儲存時又不能輸入和處理文字。

之前我們將的socket是不是通過多程序去實現過呀,如果有500個人同時和我聊天,那我是不是要起500程序啊,能行嗎?不好,對不對,那麼怎麼辦,我就可以開幾個程序,然後每個程序裡面開多個執行緒來處理多個請求和通訊。再舉例:我用qq是一個程序,然後我和一個人聊天的時候,是不是還可以去接收別人給我發的訊息啊,這個是不是並行的啊,就類似我一個程序開了多個執行緒來幫我併發接收訊息。

五 記憶體中的執行緒

  

 

    多個執行緒共享同一個程序的地址空間中的資源,是對一臺計算機上多個程序的模擬,有時也稱執行緒為輕量級的程序。

    而對一臺計算機上多個程序,則共享實體記憶體、磁碟、印表機等其他物理資源。多執行緒的執行也多程序的執行類似,是cpu在多個執行緒之間的快速切換。

    不同的程序之間是充滿敵意的,彼此是搶佔、競爭cpu的關係,如果迅雷會和QQ搶資源。而同一個程序是由一個程式設計師的程式建立,所以同一程序內的執行緒是合作關係,一個執行緒可以訪問另外一個執行緒的記憶體地址,大家都是共享的,一個執行緒乾死了另外一個執行緒的記憶體,那純屬程式設計師腦子有問題。

    類似於程序,每個執行緒也有自己的堆疊,不同於程序,執行緒庫無法利用時鐘中斷強制執行緒讓出CPU,可以呼叫thread_yield執行執行緒自動放棄cpu,讓另外一個執行緒執行。

    執行緒通常是有益的,但是帶來了不小程式設計難度,執行緒的問題是:

      1. 父程序有多個執行緒,那麼開啟的子執行緒是否需要同樣多的執行緒

      2. 在同一個程序中,如果一個執行緒關閉了檔案,而另外一個執行緒正準備往該檔案內寫內容呢?

    因此,在多執行緒的程式碼中,需要更多的心思來設計程式的邏輯、保護程式的資料。

六 使用者級執行緒和核心級執行緒

執行緒的實現可以分為兩類:使用者級執行緒(User-Level Thread)和核心線執行緒(Kernel-Level Thread),後者又稱為核心支援的執行緒或輕量級程序。在多執行緒作業系統中,各個系統的實現方式並不相同,在有的系統中實現了使用者級執行緒,有的系統中實現了核心級執行緒。 

1.使用者級執行緒

    核心的切換由使用者態程式自己控制核心切換,不需要核心干涉,少了進出核心態的消耗,但不能很好的利用多核Cpu。

      

    在使用者空間模擬作業系統對程序的排程,來呼叫一個程序中的執行緒,每個程序中都會有一個執行時系統,用來排程執行緒。此時當該程序獲取cpu時,程序內再排程出一個執行緒去執行,同一時刻只有一個執行緒執行。

2.核心級執行緒

     核心級執行緒:切換由核心控制,當執行緒進行切換的時候,由使用者態轉化為核心態。切換完畢要從核心態返回使用者態;可以很好的利用smp,即利用多核cpu。windows執行緒就是這樣的。

      

 

使用者級和核心級執行緒的對比

核心支援執行緒是OS核心可感知的,而使用者級執行緒是OS核心不可感知的。
使用者級執行緒的建立、撤消和排程不需要OS核心的支援,是在語言(如Java)這一級處理的;而核心支援執行緒的建立、撤消和排程都需OS核心提供支援,而且與程序的建立、撤消和排程大體是相同的。
使用者級執行緒執行系統呼叫指令時將導致其所屬程序被中斷,而核心支援執行緒執行系統呼叫指令時,只導致該執行緒被中斷。
在只有使用者級執行緒的系統內,CPU排程還是以程序為單位,處於執行狀態的程序中的多個執行緒,由使用者程式控制執行緒的輪換執行;在有核心支援執行緒的系統內,CPU排程則以執行緒為單位,由OS的執行緒排程程式負責執行緒的排程。
使用者級執行緒的程式實體是執行在使用者態下的程式,而核心支援執行緒的程式實體則是可以執行在任何狀態下的程式

核心級執行緒

   優點:當有多個處理機時,一個程序的多個執行緒可以同時執行。

缺點:由核心進行排程。

使用者級執行緒的優缺點:

優點:
  執行緒的排程不需要核心直接參與,控制簡單。
  可以在不支援執行緒的作業系統中實現。
  建立和銷燬執行緒、執行緒切換代價等執行緒管理的代價比核心執行緒少得多。
  允許每個程序定製自己的排程演算法,執行緒管理比較靈活。
  執行緒能夠利用的表空間和堆疊空間比核心級執行緒多。
  同一程序中只能同時有一個執行緒在執行,如果有一個執行緒使用了系統呼叫而阻塞,那麼整個程序都會被掛起。另外,頁面失效也會產生同樣的問題。
缺點:
  資源排程按照程序進行,多個處理機下,同一個程序中的執行緒只能在同一個處理機下分時複用

3.混合實現

    使用者級與核心級的多路複用,核心同一排程核心執行緒,每個核心執行緒對應n個使用者執行緒,使用者和核心都能感知到的執行緒,使用者建立一個執行緒,那麼作業系統核心也跟著建立一個執行緒來專門執行你使用者的這個執行緒。