1. 程式人生 > 其它 >python併發程式設計之執行緒

python併發程式設計之執行緒

1、為什麼要有執行緒

因為程序雖然有其優點,但也有缺點:
    1.程序只能在一個時間幹一件事,如果想同時幹兩件事或多件事,程序就無能為力了。
    2.程序在執行的過程中如果阻塞,例如等待輸入,整個程序就會掛起,即使程序中有些工作不依賴於輸入的資料,也將無法執行。

2、執行緒的出現

正因為程序的缺點,所以需要解決它。在80年代,出現了能獨立執行的基本單位——執行緒(Threads)

注意:程序是資源分配的最小單位,執行緒是CPU排程的最小單位。每一個程序中至少有一個執行緒。

3、程序和執行緒的區別

可以歸納為以下4點:

    1.地址空間和其它資源(如開啟檔案):程序間相互獨立,同一程序的各執行緒間共享。某程序內的執行緒在其它程序不可見。
    2.通訊:程序間通訊IPC,執行緒間可以直接讀寫程序資料段(如全域性變數)來進行通訊——需要程序同步和互斥手段的輔助,以保證資料的一致性。
    3.排程和切換:執行緒上下文切換比程序上下文切換要快得多。
    4.在多執行緒作業系統中,程序不是一個可執行的實體。 

4、執行緒的特點

1.輕型實體
    執行緒中的實體基本上不擁有系統資源,只是有一點必不可少的、能保證獨立執行的資源。
    執行緒的實體包括程式、資料和TCB。執行緒是動態概念,它的動態特性由執行緒控制塊TCB(Thread Control Block)描述,
      TCB用於指示被執行指令序列的程式計數器、保留區域性變數、少數狀態引數和返回地址等的一組暫存器和堆疊。

        TCB包括以下資訊:

            1.執行緒狀態。
            2.當執行緒不執行時,被儲存的現場資源。
            3.一組執行堆疊。
            4.存放每個執行緒的區域性變數主存區。
            5.訪問同一個程序中的主存和其它資源。
2.獨立排程和分派的基本單位
    在多執行緒OS中,執行緒是能獨立執行的基本單位,因而也是獨立排程和分派的基本單位。
      由於執行緒很“輕”,故執行緒的切換非常迅速且開銷小(在同一程序中的)。 
3.共享程序資源
    執行緒在同一程序中的各個執行緒,都可以共享該程序所擁有的資源,由於同一個程序內的執行緒共享記憶體和檔案,所以執行緒之間互相通訊不必呼叫核心。
4.可併發執行
    在一個程序中的多個執行緒之間,可以併發執行,甚至允許在一個程序中所有執行緒都能併發執行;
      同樣,不同程序中的執行緒也能併發執行,充分利用和發揮了處理機與外圍裝置並行工作的能力。

5、如何開啟執行緒

方法一:
    from multiprocessing import Process

    from threading import Thread


    def task():
        print("我是子執行緒")


    if __name__ == '__main__':
        t = Thread(target=task, args=())
        t.start()
        print("主執行緒")
方法二:重寫run方法
    from threading import Thread
    import time
    class Sayhi(Thread):
        def __init__(self,name):
            super().__init__()
            self.name=name
        def run(self):
            time.sleep(2)
            print('%s say hello' % self.name)

    if __name__ == '__main__':
        t = Sayhi('nick')
        t.start()
        print('主執行緒') 

6、GIL全域性直譯器鎖

1. Python在設計之初就考慮到要在主迴圈中,同時只有一個執行緒在執行
2. Python 直譯器中可以“執行”多個執行緒,但在任意時刻只有一個執行緒在直譯器中執行。

  為了實現上述,就有了GIL全域性直譯器鎖

     1、GIL鎖它是在python直譯器中的, 只在cpython中有, pypy直譯器是沒有GIL鎖的,
     2、起一個垃圾回收執行緒, 一個是正常執行的執行緒
     3、設定了一把鎖(GIL鎖),  一個執行緒要想執行,必須拿到這把鎖
     4、同一時刻,開啟一個程序,一個程序中可以有多個執行緒, 只能有一個執行緒在執行
     5、如果是計算密集型:要開程序
     6、如果是io密集型:要開執行緒  

7、執行緒間資料是共享的

import os
from threading import Thread
def work():
    global n
    n=0 
if __name__ =='__main__':
    n = 1
    t = Thread(target=work,) 
    t.start()
    t.join()
    print('主',n) # 檢視結果為0,因為同一程序內的執行緒之間共享程序內的資料 

8、守護程序

from threading import Thread
import time
def task():
    time.sleep(1)
    print("我是子執行緒")

if __name__ == '__main__':
    t = Thread(target=task,)
    t.setDaemon(True)  # 開啟守護執行緒,  主執行緒結束,子執行緒跟著結束
    t.start()
    print("主執行緒")

9、Thread類的方法

Thread例項物件的方法:
    isAlive():返回執行緒是否活動的。
    getName():返回執行緒名。
    setName():設定執行緒名。
    join():先執行完子執行緒,再執行做主執行緒

threading模組提供的一些方法:
    threading.currentThread():返回當前的執行緒變數。
    threading.enumerate():返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。
    threading.activeCount():返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果。