第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Python 進階應用教程

threading 模塊的類 Lock 的基本使用

1. 簡介

在多線程應用中,某個資源被多個線程共享訪問,線程通過使用鎖獨占該資源。需要獨占訪問的資源可能是:

  • 打印機,線程在使用打印機時,不允許其它線程向打印機輸出
  • 共享變量,線程對這個變量進行讀取訪問時,不允許其它線程同時對這個變量進行讀取訪問

python 的 threading 模塊提供了類 Lock 用于獨占訪問某個共享資源,類 Lock 提供了如下方法:

方法 功能
acquire() 獲得鎖,如果鎖是空閑的,則立即返回;如果鎖已經(jīng)被其它線程占用了,則阻塞等待。
release() 釋放鎖,喚醒等待該鎖的線程。

線程在獨占使用某個資源前,需要調(diào)用 lock.acquire() 方法,使用完畢后,需要調(diào)用 lock.release() 方法,如下所示:

lock = threading.Lock()

lock.acquire()
獨占訪問某個資源
lock.release()

2. 數(shù)據(jù)競爭

當多個線程在讀寫某個共享變量時,其最終的結(jié)果依賴于線程的執(zhí)行順序,這種現(xiàn)象被稱為數(shù)據(jù)競爭,示例如下:

import threading

sum = 0
tmp = 0
  • 引入模塊 threading
  • 設定全局變量 sum 和 tmp 的初值為 0,它們被線程共享訪問
def thread_entry():
    global sum, tmp

    for i in range(1000 * 1000):
        tmp = sum + 1
        sum = tmp
  • 在第 1 行,定義線程入口 thread_entry
  • 在第 2 行,聲明共享變量 sum 和 tmp
  • 在第 4 行,for 循環(huán) 1000* 1000 次,遞增變量 sum
t0 = threading.Thread(target = thread_entry, args = ())
t1 = threading.Thread(target = thread_entry, args = ())
t0.start()
t1.start()
t0.join()
t1.join()
print('sum =', sum)
  • 創(chuàng)建線程 t0,線程入口為 thread_entry
    • 線程 t0 對變量 sum 遞增 1000 * 1000 次
  • 創(chuàng)建線程 t1,線程入口為 thread_entry
    • 線程 t1 對變量 sum 遞增 1000 * 1000 次
  • 等待兩個線程結(jié)束后,打印 sum 的值

第一次運行程序,輸出結(jié)果如下:

sum = 1464661

再次運行程序,輸出結(jié)果如下:

sum = 1415592

線程 t0 和 t1 對 sum 各自遞增 1000 * 1000 次,期望最終的 sum 為 2 * 1000 * 1000。然而,線程 t0 和 線程 t1 共享訪問變量 sum 和 tmp,存在數(shù)據(jù)競爭,導致:

  • 實際結(jié)果依賴于線程的執(zhí)行順序,每次執(zhí)行程序的輸出結(jié)果都不一樣
  • 實際結(jié)果和預期不一致

3. 使用 lock 防止數(shù)據(jù)競爭

可以使用 threading 模塊的類 Lock 防止數(shù)據(jù)競爭,示例如下:

import threading

sum = 0
tmp = 0

def thread_entry():
    global sum, tmp

    for i in range(1000 * 1000):
        lock.acquire()  # 獲取鎖
        tmp = sum + 1
        sum = tmp
        lock.release()  # 釋放鎖

lock = threading.Lock() # 初始化鎖
t0 = threading.Thread(target = thread_entry, args = ())
t1 = threading.Thread(target = thread_entry, args = ())
t0.start()
t1.start()
t0.join()
t1.join()
print('sum =', sum)

和上個小節(jié)的例子相比,增加了 3 行代碼 (使用注釋標記):

  • lock.acquire(),訪問共享變量 sum 和 tmp 前,需要獲取鎖
  • lock.release(),訪問共享變量 sum 和 tmp 后,需要釋放鎖
  • lock = thread.Lock(),初始化鎖

第一次運行程序,輸出結(jié)果如下:

sum = 200000

再次運行程序,輸出結(jié)果如下:

sum = 200000

線程 t0 和 t1 對 sum 各自遞增 1000 * 1000 次,期望最終的 sum 為 2 * 1000 * 1000。使用了 lock 防止了數(shù)據(jù)競爭:

  • 每次執(zhí)行程序的輸出結(jié)果都是相同的
  • 實際結(jié)果和期望結(jié)果相符合