38_第五章-多线程共享数据混乱引出同步锁
一、上节回顾
总结
- 在一个进程内的所有线程共享全局变量,能够在部使用其他方式的前提下完成多线程之间的数据共享(这点要比多进程更好)
- 缺点就是,线程对全局变量随意修改可能造成多线程之间对全局变量的混乱(即线程非安全)
为了解决上述问题,需要允许线程独占的访问共享数据,这就是线程的同步。需要注意的是,这些问题在进程中也是存在的,只是在多线环境下更常见而已。
有时候需要在每个线程中使用各自独立的变量,一个显而易见的方法就是每个线程都适用自己的私有变量。为了方便,Python中提供了一种简单的机制threading.local来解决这个问题。其使用方法也很简单,就是在每个线程中建立独立私有变量。
二、实操案例
1、方法1-在每个线程中建立独立的私有变量
- 实操代码1
本方法只是逃避数据共享的操作,还需改进
- 运行结果1
2、方法2-解决线程共享数据的混乱问题
与方法1的不同:
使用全局变量
- 实操代码1:(每个进程的执行次数为5000)
- 运行结果1(无异常)
- 实操代码2:(每个进程的执行次数为500000)
- 运行结果2
按代码逻辑分析,每个进程执行500000次,最后的累计的g_num值应为2500000,此处出现错误
- 实操代码2-源代码
# -*- coding:utf-8 -*-
import time
from threading import *
g_num = 0
def run():
# print("当前进程%s,开始启动:%s"%(current_thread().name,time.time())) #开始启动时间精确到秒,这里可不打印
print("当前进程%s,开始启动"%(current_thread().name))
global g_num
for i in range(500000):
g_num += 1
print('线程%s,执行之后g_num的值为:%s'%(current_thread().name,g_num))
if __name__ == '__main__':
threads = []
for i in range(5):
t = Thread(target=run)
t.start()
threads.append(t)
for j in threads:
j.join()
print('主线程结束,g_num的值为:%s'%g_num)
- 小结
上面代码中出现的问题可分析如下:
(1)每个线程的运行次数设置小一些,运行的结果可能是正确的;
(2)问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破破坏使得线程运行的结果不可预期。这种现象称为“线程不安全”
解决方法:同步
同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。