#!/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)
#!/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 的方式,绑定线程关联的东西,其它地方使用时,会自动匹配与线程关联的值