一. Python线程互斥锁Lock
使用多线程可以同时执行多个任务,提高开发效率,但是在实际开发中往往我们会碰到线程同步问题,假如有这样一个场景:对全局变量累加1000000此,为了提高开发效率,我们可以使用多线程完成,示例代码如下:
#!/usr/bin/python
#-*- coding: utf-8 -*-# 导入线程threading模块
import threading
# 声明全局变量
g_num= 0def my_thread1():
# 声明全局变量globalg_num
# 循环1000000 次,每次累计加 1
for i in range(0, 1000000):
g_num= g_num + 1def my_thread2():
# 声明全局变量globalg_num
# 循环1000000 次,每次累计加 1
for i in range(0, 1000000):
g_num= g_num + 1def main():
# 声明全局变量globalg_num
# 初始化全局变量,初始值为0# 创建两个线程,对全局变量进行累计加1t1= threading.Thread(target=my_thread1)
t2= threading.Thread(target=my_thread2)
# 启动线程
t1.start()
t2.start()
# 阻塞函数,等待线程结束
t1.join()
t2.join()
# 获取全局变量的值
print("计算结果:%d" %(g_num))if __name__ == "__main__":
main()
执行结果:
这个是什么操作?看着代码好像也没问题,两个线程,各自累加1000000次,不应该输出的是2000000吗?
1. 线程共享全局变量
分析上面的代码:两个线程共享全局变量并执行for循环1000000,每次自动加1,我们都知道两个线程都是在同时运行,也就是说两个线程同时在执行g_num = g-num = 1操作,经过我们冷静分析一波,貌似结果该是应该等于2000000,对不对?
首先我们将上面的全局变量自动加1的代码分为两步:
第一步: g_num + 1
第二步: 将g_num + 1的结果赋值给g_num
由此可见,执行一个完整的自动加1的过程需要两步,然而线程确是同时在运行,谁也不能保证线程1的第一步和第二部执行完成之后才执行线程2的第一步和第二步,执行的过程充满随机性,这就是导致每次计算结果不同的原因所在。
2. 线程互斥锁
为了避免上面的问题,我们可以利用线程互斥锁解决这个问题,那么线程互斥锁到底是个什么原理呢?互斥锁就好比排队上厕所,一个坑位只能蹲一个人,只有占用坑位的人完事了,另一个人才能上!!
创建互斥锁
导入线程模块,通过threading.Lock()创建互斥锁
import threading
mutex= threading.Lock()
锁定资源/解锁资源
acquire() --锁定资源,此时资源是锁定状态,其他线程无法修改锁定的资源,知道等待锁定的资源释放之后才能操作
release() --释放资源,也成为解锁操作,对锁定的资源解锁,解锁之后其他线程可以对资源正常操作
上面的代码为例子:想得到正确的结果,可以直接利用互斥锁在全局变量加1之前锁定资源,然后在计算完成之后释放资源,这样就是一个完整的计算过程,至于应该是那个线程先执行,无所谓,先到先得,凭本事说话
#!/usr/bin/python
#-*- coding: utf-8 -*-# 导入线程threading模块
import threading
mutex=threading.Lock()
# 声明全局变量
g_num= 0def my_thread1():
# 声明全局变量globalg_num
# 循环1000000 次,每次累计加 1
for i in range(0, 1000000):
mutex.acquire()
g_num= g_num + 1mutex.release()
def my_thread2():
# 声明全局变量globalg_num
# 循环1000000 次,每次累计加 1
for i in range(0, 1000000):
mutex.acquire()
g_num= g_num + 1mutex.release()
def main():
# 声明全局变量globalg_num
# 初始化全局变量,初始值为0# 创建两个线程,对全局变量进行累计加1t1= threading.Thread(target=my_thread1)
t2= threading.Thread(target=my_thread2)
# 启动线程
t1.start()
t2.start()
# 阻塞函数,等待线程结束
t1.join()
t2.join()
# 获取全局变量的值
print("计算结果:%d" %(g_num))if __name__ == "__main__":
main()
执行结果: