1. 程式人生 > >線程模塊threading

線程模塊threading

eth 過程 數字 run info port 用戶 全局 proc

線程 -Threading模塊 -使用和進程基本相似

  • 多線程中是可以input
  • 在使用的過程中從用戶層面上並沒有感覺到和進程的差別,但是有本質差別
  • 執行代碼的最小單元
  • 每一個進程至少有一個線程,這個線程是主線程
  • 一個進程內的所有線程之間的數據是共享的

      #啟動多線程
      from threading import Thread
      import time
    
      def func(i):
          time.sleep(1)
          print(i)
    
      for i in range(10):
          t = Thread(target=func, args=(i,))
          t.start()
      print(‘這是主線程執行的‘)
      #結果
      這是主線程執行的
      0
      2
      1
      3
      4
      5
      9
      8
      6
      7   #這裏的十個數字是幾乎同時被輸出,說明是個線程並發
  • 面向對象的形式啟動線程

      #用面向對象的方法開啟新的線程
      from threading import Thread
      class MyThread(Thread): #繼承Thread類
          def __init__(self, arg): #重寫__init__方法,用於給這個類傳參
              super().__init__()  #繼承父類的__init__方法
              self.arg = arg  #將自己的參數賦給對象
    
          def run(self):                  
          ‘‘‘objece.start()直接調用這個方法‘‘‘
              self.methond()
    
          def methond(self):
              ‘‘‘這個類中的其他方法‘‘‘
              print(self.arg) 

進程|主線程|子線程

  • 進程是最小的內存分配單位
  • 線程是操作系統調度的最小單位
  • 線程被cpu執行了
  • 進程中可以有多個線層,至少一個主線程
  • 主線程
  • 子線程
    • 子線程的數據儲存在棧中
  • 全局變量global n線程共享

線程鎖 -這是解釋語言的一個不可避免的問題

  • 全局解釋器鎖 -鎖的是線程
    • 同一時刻只能有一個線程訪問cpu

進程和線程的效率對比 -線程快

from multiprocessing import Process
from threading import Thread
import time

def cal_num(i):
    i += 1

if __name__ == ‘__main__‘:
    p_list = []
    start = time.time()
    for i in range(100):    #創建100個進程執行計算
        p = Process(target=cal_num, args=(i, ))
        p.start()
        p_list.append(p)
    for i in p_list:
        i.join()
    end = time.time()
    t1 = end - start


start = time.time()
t_list = []
for i in range(100):
    t = Thread(target=cal_num, args=(i,))
    t.start()
    t_list.append(t)
for i in t_list:
    i.join()
end = time.time()
t2 = end - start
print(‘100個進程消耗時間{} \n 100個線程消耗時間{}‘.format(t1, t2))
#結果
100個進程消耗時間0.19627618789672852  
100個線程消耗時間0.009418964385986328

線程中的其他方法 -threading.方法名()

  • threading.current_thread() 所有進程的情況
  • .get_ident() 查看進程的id
  • .active_count() 查看活躍進程的數量
  • .enumerate() 所有的進程情況放進一個列表中

守護線程 -守護線程和進程的區別

  • 將子線程設置成守護線程,守護線程將在主線程代碼執行結束且其他線程執行結束後結束
  • 但是守護進程是在主進程結束之後結束,不等待其他子進程是否結束

線程鎖 -Lock()和RLock

科學家吃面模型 -死鎖模型

  • Lock()的死鎖現象
  • Lock()互斥鎖,只有一把鑰匙
  • RLock()遞歸鎖,只要拿到一把,就等於拿到一串,必須等一串全部歸還下個線程才能繼續拿鑰匙
    • 死鎖情況

        #死鎖情況
        from threading import Thread,Lock   
        from time import sleep
        #死鎖情況
        from threading import Thread,Lock,RLock
        from time import sleep
      
        mt_lock = Lock()
        cz_lock = Lock()
        def miantao():
            mt_lock.acquire()
            print(‘拿到面條了‘)
            sleep(1)
            cz_lock.acquire()
            print(‘拿到叉子了‘)
            print(‘吃面‘)
            mt_lock.release()
            cz_lock.release()
      
        def chazi():
            cz_lock.acquire()
            print(‘拿到叉子了‘)
            sleep(1)
            mt_lock.acquire()
            print(‘拿到面條了‘)
            print(‘吃面‘)
            cz_lock.release()
            mt_lock.release()
      
        th1 = Thread(target=miantao, args=())
        th2 = Thread(target=chazi, args=())
        th1.start()
        th2.start()
    • 解決死鎖問題RLock()

        from threading import Thread, Lock, RLock
        from time import sleep
      
        cz_lock = mt_lock = RLock() #這裏創建遞歸鎖
        def miantao():
            mt_lock.acquire()
            print(‘拿到面條了‘)
            sleep(1)
            cz_lock.acquire()
            print(‘拿到叉子了‘)
            print(‘吃面‘)
            mt_lock.release()
            cz_lock.release()
      
        def chazi():
            cz_lock.acquire()
            print(‘拿到叉子了‘)
            sleep(1)
            mt_lock.acquire()
            print(‘拿到面條了‘)
            print(‘吃面‘)
            cz_lock.release()
            mt_lock.release()   
      
        th1 = Thread(target=miantao, args=())
        th2 = Thread(target=chazi, args=())
        th1.start()
        th2.start()

信號量 -同進程

  • 限制一段代碼有且只有n個線程同時調用

事件 -同進程

  • 創建就為阻塞狀態

    實例 -鏈接數據庫,以及數據庫的可連接的情況

      from threading import Thread, Event
    
      e = Event()
      def test():
          ‘‘‘檢測數據庫的連通性‘‘‘
          info = input(‘>>‘)
          if info == ‘1‘:
              e.set()
              print(‘數據庫網絡連接打開‘)
          else:
              print(‘關閉數據庫網絡連接‘)
      def connect_q():
          ‘‘‘連接數據庫‘‘‘
          print(‘等待數據庫網絡連接‘)
          e.wait()
          print(‘數據庫連接成功!‘)   
    
      t1 = Thread(target=test)
      t2 = Thread(target=connect_q)
      t1.start()
      t2.start() 

條件 -Condition

  • .acquire() #鑰匙
  • .release() #釋放鑰匙
  • .notify(num) #允許鑰匙串有幾把鑰匙
  • .wait() #等待.notify(num)提供鑰匙數量

      #條件
      from threading import Condition, Thread
    
      def print_thrad(con, i):
          con.acquire()   #這裏也有鎖
          con.wait()
          print(‘第{}線程運行了‘.format(i)) 
          con.release()
    
      num = int(input(‘>>‘))
      con = Condition()
    
    
      for i in range(10):
          t = Thread(target=print_thrad, args=(con, i))
          t.start()
    
      con.acquire()   #這裏也有鎖
      con.notify(num) #前後必須有鑰匙和鎖
      con.release()

定時器 -Timer()

  • 定時開啟一個線程
  • 用法和Threa()一致

      from threading import Timer
    
      def func():
          print(‘兩秒時間到了‘)
      Timer(2, func).start()
      print(‘呵呵‘)
      #結果
      呵呵
      兩秒時間到了  #子線程兩秒後才開啟

線程隊列 -queue.Queue()

  • .put() 放元素
  • .put_nowait() #放元素,沒有元素報錯
  • .get() #取出元素
  • .get_nowait() #沒有元素報錯

其他隊列模塊中的類

先進後出 LifoQueue()

優先級隊列 PriorityQueue()

線程模塊threading