關於多線程下變量賦值取值的一點研究
by:授客 QQ:1033553122
1.代碼實踐1
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'shouke'
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time
class TestClass:
def __init__(self, num):
self.num = num
global_var = 0
def testfn(num, obj):
global global_var
global_var = num
local_var = num * 2
obj.num = num * 2
time.sleep(5)
print("thread id:", threading.get_ident(), 'num:', num, 'obj.num:', obj.num, 'local_var:', local_var, 'global_var:', global_var)
for i in range(0, 5):
# # 多線程執行性能監控
thread = threading.Thread(target=testfn,
name="testfn"+str(i),
args=(i, TestClass(i)))
thread.start()


結論:
1、如下,通過args給線程即將調用函數(為方便描述,暫且稱它為 “線程函數”)傳遞參數,可以做到每個線程都使用各自的參數去調用線程函數。
thread = threading.Thread(target=testfn,
name="testfn"+str(i),
args=(i, TestClass(i)))
2、如下,線程函數里的局部變量(例中除去global_var之外的變量),都存儲在棧內存中,而每個線程都有自己的棧內存,彼此獨立,所以,每個線程對局部變量的賦值,讀取操作互不影響。也就是說,多線程並發的情況下,局部變量是“安全”的,而全局變量存儲在堆內存中,堆內存為所有線程共享,對所有線程都是可見的,所以兩個以上的線程訪問全局變量時,就會出現所謂的“不安全”,如下,第一個線程訪問了全局變量 global_var,賦值為對應的num,然后中間sleep了5秒,在此期間,另一個線程訪問了全局變量,賦值為另一個num,然后第一個線程醒來了,發現全局變量 global_var 已經不是它要的值了。
def testfn(num, obj):
global global_var
global_var = num
local_var = num * 2
obj.num = num * 2
time.sleep(5)
2.代碼實踐2
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time
thread_local_obj = threading.local()
class TestClass:
def __init__(self, num):
self.num = num
global_var = 0
def testfn(num, obj):
global global_var
global_var = num
local_var = num * 2
obj.num = num * 2
thread_local_obj.obj = obj
time.sleep(5)
other_task()
print("thread id:", threading.get_ident(), 'num:', num, 'obj.num:', obj.num, 'local_var:', local_var, 'global_var:', global_var)
def other_task():
print("thread id:", threading.get_ident(), 'obj.num:', thread_local_obj.obj.num , threading.currentThread().name)
for i in range(0, 5):
# # 多線程執行性能監控
thread = threading.Thread(target=testfn,
name="testfn"+str(i),
args=(i, TestClass(i)))
thread.start()


如上,線程函數中調用了另一個函數,我們希望在這個函數中做些操作,比如讀取和線程關聯的對象的屬性值、修改屬性值,這個按常規思維也可以通過傳遞函數參數來實現, 如下
other_task(obj):
print(obj.num)
問題是,線程函數里可能會調用多個函數,被調用的每個函數也可能會調用多個函數,所有這些函數都可能用到線程關聯的對像,這樣的話,需要逐層傳遞參數,很麻煩
解決方案:
創建全局對象,如下
thread_local_obj = threading.local()
然后在 線程函數 里通過 thread_local_obj.attr = xxx 的方式,綁定線程關聯的東西,其它地方使用時,會自動匹配與線程關聯的值
