1. 程式人生 > >執行緒,共享資源,鎖

執行緒,共享資源,鎖

執行緒的概念

程序的概念:執行著的程式
每個程序裡面至少有一個執行緒
執行緒是作業系統建立的,用力啊控制程式碼執行的資料結構
執行緒就像程式碼的執行許可證

單執行緒程式。主執行緒的入口就是程式碼的開頭
主執行緒順序往下執行,直到所有的程式碼都執行完

**

概念對應(銀行裡面辦理業務)

**
一個服務視窗 = CPU的一個核
客戶 = 程序(執行著的程式)
排程員 = 作業系統(OS)
服務號 = 執行緒
排程員分配服務號給客戶 = OS分配執行緒給程序程式碼
服務視窗給客戶辦理業務 = CPU核心執行執行緒程式碼

排程的概念

    排程員分配視窗給客戶
    一個客戶不一定佔用一個視窗直到它結束
    比如需要很長時間填寫表格
    這是可以讓下一個客戶辦理
    先前的客戶填好了表格,在繼續

作業系統不會讓一個執行緒一直佔用CPU的

程序裡的多執行緒

執行緒庫
程式碼通過系統呼叫,請求os分配一個新的執行緒
python裡面使用封裝好的庫,python3只有threading,是標準庫裡面的
thread
threading
都可以用來建立和管理執行緒
thread比較底層
threading是thread模組的擴充套件,提供了很多執行緒同步功能,使用起來更加方便強大

例子:

print("main thread start.")

import threading
from time import sleep

def thread1_entry():
    print("child thread 1,start")
    sleep(15)
    print("child thread 1,end")

t1 = threading.Thread(target=thread1_entry)    #Thread是一個類Thread()是例項化一個類,傳入初始化方法的引數,target傳的是這個函式的名字,不是呼叫。不加括號是函式的物件。
t1.start()     #t1是Thread的例項物件,從這個點開始就啟動了一個新的執行緒
sleep(10)    #主執行緒要sleep10秒    主執行緒先結束
print("main thread end.")

#結果

main thread start.
child thread 1,start
main thread end.
child thread 1,end

有些場景是:主執行緒要等待子執行緒執行完,比如子執行緒爬去資料,主執行緒分析資料、
要等到子執行緒結束(執行緒的.join()方法)

import threading
from time import sleep,ctime,time

def thread1_entry(nsec):
    print("child thread 1,start at:",ctime())
    sleep(nsec)
    print("child thread 1,end at:",ctime())


def thread2_entry(nsec):
    print("child thread 2,start at:",ctime())
    sleep(nsec)
    print("child thread 2,end at:",ctime())


print("main thread start.")
#建立執行緒物件,指定了新執行緒的入口函式,args是傳入入口函式的引數
t1 = threading.Thread(target=thread1_entry,args=(1,))    #Thread是一個類Thread()是例項化一個類,傳入初始化方法的引數
t2 = threading.Thread(target=thread2_entry,args=(2,))   #(1,)元組,args=(1,)是入口函式的引數,就是用args傳給他,只能傳元組,一個元素的時候,一定要加逗號,這裡是傳入的是時間

#啟動新執行緒
t1.start()   #兩個執行緒的例項化。呼叫start方法
t2.start()

start = time()    #驗證json等待的時間

#主執行緒等待t1執行緒結束,
t1.join()
#主執行緒等待t2執行緒結束
t2.join()

end = time()        #驗證json等待的時間
print(end-start)        #驗證json等待的時間

print("main thread end.")

#結果:

# main thread start.
# child thread 1,start at: Sat Nov 10 18:06:26 2018
# child thread 2,start at: Sat Nov 10 18:06:26 2018
# child thread 1,end at: Sat Nov 10 18:06:27 2018
# child thread 2,end at: Sat Nov 10 18:06:28 2018
# 2.0
# main thread end.

多執行緒使用共享資料

共享物件的概念

從例子說起
高鐵上的測試
某個時刻只能一個人使用
進入後往往立刻鎖門(表示已經被使用)
看到的人,門口排隊等待
用完開鎖(表示已經使用完了)
排隊的人中下一個去使用(重複這個過程)

有些資源是某個時刻時刻獨佔使用的
如果不加鎖
某人使用廁所
另一個人也進入使用
發生衝突
鎖保證了
只有一個人去使用
別人必須等待

 import threading
 from time import sleep,ctime,time

#儲存支付寶賬號餘額
zhifubao = {
    "jcy":100000,
    "liming":5000,
    "wangmin":15000,
    "zhaolei":6500000,
}
#執行緒1:滴滴打車處理,引數是使用者賬戶和扣款金額
def thread1_didi_pay(account,amount):
    print("* t1:get balance from bank")
    balance = zhifubao[account]    #通過賬戶把餘額取出來,放到一個變數裡面

    #下面的sleep(2)表示一些處理過程中需要花上2秒鐘
    print("* t1:do something(like discount lookup) for 2 seconds")
    sleep(2)

    print("* t1:deduct")

    zhifubao[account] = balance - amount    #把餘額扣掉

#執行緒2:餘額寶處理,引數是使用者賬戶和當前利息

def thread2_yuebao_interest(account, amount):
    print("$ t2:get balance from bank")
    balance = zhifubao[account]

    # 下面的sleep(1)表示一些處理過程中需要花上1秒鐘
    print("$ t2:do something2...... for 2 seconds")
    sleep(1)

    print("$ t2: add")

    zhifubao[account] = balance + amount    ##餘額每天的收益


t1 = threading.Thread(target=thread1_didi_pay,args=("jcy",10))  #創立兩個執行緒物件
t2 = threading.Thread(target=thread2_yuebao_interest,args=("jcy",10))

t1.start()
t2.start()

t1.join()
t2.join()
print("finally,jcy balance is %s"%zhifubao["jcy"])

#結果

# * t1:get balance from bank
# * t1:do something(like discount lookup) for 2 seconds
# $ t2:get balance from bank
# $ t2:do something2...... for 2 seconds
# $ t2: add
# * t1:deduct
# finally,jcy balance is 99990

#應該是10萬元
#多個執行緒要訪問共享資料的時候,特別是要修改資料的時候。我們可以使用鎖物件的機制。同時只有一個執行緒處理他的時候,就不會有問題

import threading
from time import sleep,ctime,time

#儲存支付寶賬號餘額
zhifubao = {
    "jcy":100000,
    "liming":5000,
    "wangmin":15000,
    "zhaolei":6500000,
}

#呼叫Lock函式,返回一個鎖物件
zhifubao_lock = threading.Lock()

#執行緒1:滴滴打車處理,引數是使用者賬戶和扣款金額
def thread1_didi_pay(account,amount):
    #在程式碼訪問共享物件之前,加鎖
    #當多個執行緒同時執行lock.acquire()時,
    #只有一個執行緒能成功的獲取鎖,然後繼續執行程式碼
    #其他執行緒就繼續等待,直到獲得鎖為止
    zhifubao_lock.acquire()
    print("* t1:get balance from bank")
    balance = zhifubao[account]    #通過賬戶把餘額取出來,放到一個變數裡面

    #下面的sleep(2)表示一些處理過程中需要花上2秒鐘
    print("* t1:do something(like discount lookup) for 2 seconds")
    sleep(2)

    print("* t1:deduct")

    zhifubao[account] = balance - amount    #把餘額扣掉
    #訪問共享物件釋放鎖
    #訪問結束後,一定要呼叫Lock物件的release方法,進行解鎖操作
    #否則其他等待鎖的執行緒將永遠等待下去
    zhifubao_lock.release()
#執行緒2:餘額寶處理,引數是使用者賬戶和當前利息

def thread2_yuebao_interest(account, amount):
    zhifubao_lock.acquire()   #程式碼訪問共享物件之前,加鎖
    print("$ t2:get balance from bank")
    balance = zhifubao[account]

    # 下面的sleep(1)表示一些處理過程中需要花上1秒鐘
    print("$ t2:do something2...... for 2 seconds")
    sleep(1)

    print("$ t2: add")

    zhifubao[account] = balance + amount    ##餘額每天的收益
    zhifubao_lock.release()    #訪問完共享物件 釋放鎖

t1 = threading.Thread(target=thread1_didi_pay,args=("jcy",10))  #創立兩個執行緒物件
t2 = threading.Thread(target=thread2_yuebao_interest,args=("jcy",10))

t1.start()
t2.start()

t1.join()
t2.join()
print("finally,jcy balance is %s"%zhifubao["jcy"])

#結果

# * t1:get balance from bank
# * t1:do something(like discount lookup) for 2 seconds
# * t1:deduct
# $ t2:get balance from bank
# $ t2:do something2...... for 2 seconds
# $ t2: add
# finally,jcy balance is 100000    

在這裡插入圖片描述