关于多线程下变量赋值取值的一点研究
1.代码实践1
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ ='shouke'
#!/usr/bin/env python
# -*- coding:utf-8 -*-
importthreading
importtime
classTestClass:
def__init__(self, num):
self.num = num
global_var =0
deftestfn(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)
foriinrange(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 已经不是它要的值了。
deftestfn(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 -*-
importthreading
importtime
thread_local_obj = threading.local()
classTestClass:
def__init__(self, num):
self.num = num
global_var =0
deftestfn(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)
defother_task():
print("thread id:", threading.get_ident(),'obj.num:', thread_local_obj.obj.num , threading.currentThread().name)
foriinrange(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 的方式,绑定线程关联的东西,其它地方使用时,会自动匹配与线程关联的值