python多任務編程---線程

線程編程(Thread)

  • 什麼是線程
  1. 線程被稱爲輕量級的進程
  2. 線程也可使用計算機多核資源,是多任務編程方式
  3. 線程是系統分配內核的最小單元
  4. 線程能夠理解爲進程的分支任務
  • 線程特徵
  1. 一個進程中能夠包含多個線程
  2. 線程也是一個運行行爲,消耗計算機資源
  3. 一個進程中的全部線程共享這個進程的資源
  4. 多個線程之間的運行互不影響各自運行
  5. 線程的建立和銷燬耗資源小於進程
  6. 各個進程也有本身的ID等特徵

threading模塊建立線程

建立線程對象python

from threading import Thread 

t = Thread()
功能:建立線程對象
參數:target 綁定線程函數
     args   元組 給線程函數位置傳參
     kwargs 字典 給線程函數鍵值傳參

啓動線程編程

t.start()

回收線程後端

t.join([timeout])

線程基礎使用示例:多線程

 1 import threading
 2 from time import sleep
 3 import os
 4 
 5 a = 1
 6 
 7 # 線程函數
 8 def music():
 9     global a
10     print("a = ",a)
11     a = 10000
12     for i in range(3):
13         sleep(2)
14         print(os.getpid(),"播放: 葫蘆娃")
15 
16 # 線程對象
17 t = threading.Thread(target = music)
18 t.start() # 啓動線程
19 
20 for i in range(4):
21     sleep(1)
22     print(os.getpid(),"播放: 黃河大合唱")
23 
24 t.join() # 回收線程
25 
26 print("===========================")
27 
28 print("a:",a)
View Code

 

線程基礎實例2:併發

 1 from threading import Thread
 2 from time import sleep
 3 
 4 # 含有參數的線程函數
 5 def fun(sec,name):
 6     print("線程函數傳參")
 7     sleep(sec)
 8     print("%s執行完畢"%name)
 9 
10 # 建立多個線程
11 jobs=[]
12 for i in range(3):
13     t = Thread(target=fun,args=(2,),
14                kwargs={'name':'T%d'%i})
15     jobs.append(t)  # 存線程對象
16     t.start()
17 
18 for i in jobs:
19     i.join()
View Code

 

線程對象屬性

t.name 線程名稱app

t.is_alive() 查看線程是否在生命週期前後端分離

t.daemon 設置主線程和分支線程的退出關係編程語言

t.setDaemon() 設置daemon屬性值ide

t.isDaemon() 查看daemon屬性值函數

  daemon爲True時主線程退出分支線程也退出。要在start前設置,一般不和join一塊兒使用。

自定義線程類

  • 建立步驟
  1. 繼承Therad類
  2. 重寫__init__方法添加本身的屬性,使用super()加載父類屬性
  3. 重寫run()方法
  • 使用方法
  1. 實例化對象
  2. 調用start自動執行run方法
  3. 調用join回收線程

自定義線程示例:

 1 from threading import Thread
 2 from time import sleep,ctime
 3 
 4 class MyThread(Thread):
 5     # __init__能夠添加參數,進行編寫
 6     def __init__(self,target,args=(),kwargs={}):
 7         super().__init__() # 此處不準傳參
 8         self.target = target
 9         self.args = args
10         self.kwargs = kwargs
11 
12     # 添加其餘方法 run
13     def run(self):
14         self.target(*self.args,**self.kwargs)
15 
16 ###########################################
17 def player(sec,song):
18     for i in range(3):
19         print("Playing %s:%s"%(song,ctime()))
20         sleep(sec)
21 
22 t = MyThread(target=player,args=(3,),
23              kwargs={'song':'涼涼'})
24 
25 t.start()
26 t.join()
View Code

 

同步互斥

線程間通訊方法

通訊方法

線程間使用全局變量進行通訊

共享資源爭奪

共享資源:多個進程或者線程均可以操做 的資源稱爲共享資源.對共享資源的操做代碼段稱爲臨界區

影響:對共享資源的無需操做可能會帶來數據的混亂,或者操做錯誤.此時每每須要同步互斥機制協調操做順序

同步互斥機制

同步:同步是一種協做關係,爲完成操做,多進程或者多線程間造成一種協調,按照必要的步驟有序執行操做

互斥:互斥是一種制約關係,當一個進程或者線程佔有資源時會進行加鎖處理,此時其餘進程就沒法操做該資源,直到解鎖後才能操做.

 線程同步互斥方法

線程Event

from threading import Event

e = Event()  建立線程event對象

e.wait([timeout])  阻塞等待e被set

e.set()  設置e,使wait結束阻塞

e.clear() 使e回到未被設置狀態

e.is_set()  查看當前e是否被設置

 互斥代碼示例:

 

from threading import Thread,Event

s = None  # 全局變量用於通訊
e = Event() # 事件對象

def 楊子榮():
    print("楊子榮前來拜山頭")
    global s
    s = "天王蓋地虎"
    e.set() # 修改完s

t = Thread(target=楊子榮)
t.start()

print("說對口令就是本身人")
e.wait() #阻塞等待
if s == "天王蓋地虎":
    print("寶塔鎮河妖")
    print("確認過眼神,你是對的人")
else:
    print("打死他!!")

t.join()
View Code

 

 

線程鎖Lock

from  threading import Lock

lock = Lock()  建立鎖對象
lock.acquire() 上鎖  若是lock已經上鎖再調用會阻塞
lock.release() 解鎖

with  lock:  上鎖

線程鎖代碼示例:

 

 1 from threading import Thread,Lock
 2 
 3 a = b = 0
 4 lock = Lock() # 鎖對象
 5 
 6 def value():
 7     while True:
 8         lock.acquire()
 9         if a != b:
10             print('a = %d,b = %d'%(a,b))
11         lock.release() # 解鎖操做
12 
13 t = Thread(target=value)
14 t.start()
15 
16 while True:
17     with lock:  # with上鎖
18         a += 1
19         b += 1
20                 # 語句塊結束解鎖
21 t.join()
View Code

 

 死鎖及其處理

定義

死鎖是指兩個或者兩個以上的線程在執行過程當中,因爲競爭資源或者因爲彼此通訊而總成的一種阻塞的現象,若無外力做用,他們都將沒法推動下去.此時稱系統處於死鎖狀態或系統產生了死鎖

死鎖產生條件

死鎖代碼示例:

 1 from time import sleep
 2 from threading import Thread,Lock
 3 
 4 # 交易類
 5 class Account:
 6     def __init__(self,_id,balance,lock):
 7         self.id = _id  #
 8         self.balance = balance # 有多少錢
 9         self.lock = lock #
10 
11     # 取錢
12     def withdraw(self,amount):
13         self.balance -= amount # 取多少
14 
15     # 存錢
16     def deposit(self,amount):
17         self.balance += amount # 存多少
18 
19     # 查看餘額
20     def get_balance(self):
21         return self.balance
22 
23 # 建立兩個帳戶
24 Tom = Account('Tom',5000,Lock())
25 Alex = Account('Alex',8000,Lock())
26 
27 # 轉帳行爲
28 def transfer(from_,to,amount):
29     # 從 from_ --> to  轉amount
30     if from_.lock.acquire(): # 鎖住本身帳戶
31         from_.withdraw(amount) # 本身帳戶扣除
32         sleep(0.5)
33         if to.lock.acquire(): # 對方帳戶上鎖
34             to.deposit(amount) # 對方帳戶增長
35             to.lock.release() # 對方解鎖
36         from_.lock.release() # 本身解鎖
37     print("%s給%s轉了%d"%(from_.id,to.id,amount))
38 
39 t1 = Thread(target=transfer,args=(Tom,Alex,2000))
40 t2 = Thread(target=transfer,args=(Alex,Tom,3500))
41 
42 t1.start()
43 t2.start()
44 
45 t1.join()
46 t2.join()
47 
48 print(Tom.get_balance())
49 print(Alex.get_balance())
View Code  
  •  死鎖發生的必要條件
  1. 互斥條件:指線程對全部分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程佔用.若是此時還有其餘進程請求資源,則請求者只能等待.直至佔有資源的進程用完畢釋放
  2. 請求和保持條件:指線程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求線程阻塞,但又對本身已或得的其餘資源保持不放
  3. 不剝奪條件:指線程已得到的資源,在未使用完以前,不能被剝奪,只能在使用完時由本身釋放,一般CPU內存資源是能夠被系統強行調配剝奪的.
  4. 環路等待條件:指在發生死鎖時,必然存在一個線程------資源的環形鏈,即進程集合

    {T0,T1,T2,....,Tn}中正在等待一個T1佔用的資源;T1正在等待T2佔用的資源,......,Tn正在等待已被T0佔用的資源.

  • 死鎖的產生緣由
  • 簡單來講形成死鎖的緣由能夠歸納成三句話:
  1. 當前線程擁有其餘線程須要的資源
  2. 當前線程等待其餘線程已擁有的資源
  3. 都不放棄本身擁有的資源
  • 如何避免死鎖

  死鎖是咱們很是不肯意看到的一種現象,咱們要儘量避免死鎖的狀況發生.經過設置某些條件限制條件,去破壞產生死鎖的四個必要條件中的一個或者幾個,,來預防發生死鎖.預防死鎖是一種較易實現的方法.可是因爲所施加的限制條件每每太嚴格,可能致使系統資源利用率.

python線程GIL

 python線程的GIL問題(全局解釋鎖)

  • 什麼是GIL:因爲python解釋器設計中加入瞭解釋器鎖,致使python解釋器同一時刻只能解釋執行一個線程,大大下降了線程的執行效率
  • 致使後果:由於遇到阻塞時線程會主動讓出解釋器,去解釋其餘線程.因此python多線程在執行多阻塞高延遲IO時能夠提高程序效率,其餘狀況並不能對效率有所提高  

GIL問題建議

  1. 儘可能使用進程完成無阻塞的併發行爲
  2. 不使用C做爲解釋器(Java  C#)

進程線程的區別聯繫

區別聯繫

  1. 二者都是多任務編程方式,都能使用計算機多核資源
  2. 進程的建立刪除消除的計算機資源比線程多
  3. 進程空間獨立,數據互不干擾,有專門通訊方法;線程使用全局變量通訊
  4. 一個進程能夠有多個分支線程,二者有包含關係
  5. 多個線程共享進程資源,在共享資源操做時每每須要同步互斥處理
  6. 進程線程在系統中都有本身的特有屬性標誌,如ID,代碼段,命令集等

使用場景

  1. 任務場景:若是是相對獨立的任務模塊,可能使用多進程,若是是多個分支共同造成一個總體任務可能用多線程
  2. 項目結構:多種編程語言實現不一樣任務模塊,多是多進程,或者先後端分離應該各自爲一個進程
  3. 難易程度:通訊難度,數據處理的複雜度來判斷用進程間通訊仍是同步互斥方法

要求

  1. 對進程線程怎麼理解/說說進程線程的差別
  2. 進程間通訊知道那些,有什麼特色
  3. 什麼是同步互斥,你什麼狀況下使用,怎麼用
  4. 給一個情形,說說用進程仍是線程,爲何
  5. 問一些概念,殭屍進程的處理,GIL問題,進程狀態
相關文章
相關標籤/搜索