多線程局部變量之threading.local()用法


假如,開了十個線程並且做同樣的一件事,他們需要帶着自己的數據進來,完成事情后帶着自己的數據出去。如果是並發,同時進來,他們的數據就會混亂。

一般情況,我們加鎖就可以了,一個人先進來,先加鎖,另一個人過來看到加鎖了,就在外面等,等里面的人出來,自己進去加鎖,這樣就不會出現數據混亂的問題。

另一種解決方法就是threading.local()來解決問題。

先看下面這個現象

from threading import Thread

ret = -1  # 先定義一個變量


def task(arg):  # 寫個任務,加個參數
    global ret  # 聲明ret全局變量
    ret = arg  # 每一個線程進來到要改這個變量
    print(ret)  # 每個線程來,改了ret,然后取ret的值


for i in range(10):  # i是線程的值,0 1 2 3 4 5 6 7 8 9
    t = Thread(target=task, args=(i,))  # 開10個線程
    t.start()
# 打印結果 0 1 2 3 4 5 6 7 8 9

這個程序開了10個線程,每個線程都執行了更改ret的值並獲取ret更改后的值,如果非常快,他們取到的值都不一樣.

如果讓他們睡兩秒再執行

from threading import Thread
import time

ret = -1  # 先定義一個變量


def task(arg):  # 寫個任務,加個參數
    global ret  # 聲明ret全局變量
    ret = arg  # 每一個線程進來到要改這個變量
    time.sleep(2)
    print(ret)  # 每個線程來,改了ret,然后取ret的值


for i in range(10):  # i是線程的值,0 1 2 3 4 5 6 7 8 9
    t = Thread(target=task, args=(i,))  # 開10個線程
    t.start()
# 打印結果 9 9 9 9 9 9 9 9 9 9

打印結果全是9

那么解決這個問題我們可以用threading.local()方法

from threading import Thread
from threading import local
import time
# 這是一個特殊的對象
ret = local()  # 先實例化一個對象


def task(arg):  # 寫個任務,加個參數
    ret = arg  # 每一個線程進來都給他開辟一個獨立的空間  單純的threading.local()的作用就是這個
    time.sleep(2)
    print(ret)  # 每個線程來,改了ret,然后取ret的值


for i in range(10):  # i是線程的值,0 1 2 3 4 5 6 7 8 9
    t = Thread(target=task, args=(i,))  # 開10個線程
    t.start()
# 打印結果 0 3 2 5 7 9 8 4 1 6
threading.local()的作用就是為每個線程開辟一個獨立的空間進行數據存儲。

接下來我們自定義local對象
from threading import get_ident,Thread
import time

storage = {}


def set(k,v):  # 來給storage設置值
    ident = get_ident()  # get_ident()能獲取唯一標識,是一組數字
    if ident in storage:
        storage[ident][k] = v
    else:
        storage[ident] = {k:v}


def get(k):  # 來取storage的值
    ident = get_ident()
    return storage[ident][k]


def task(arg):
    set('val',arg)
    v = get('val')
    print(v)


for i in range(10):
    t = Thread(target=task,args=(i,))
    t.start()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM