前言
在这里记录一下我学习线程锁的一些笔记
1.为什么要使用线程锁?
使用线程锁的作用是为了保证数据的安全.
举个例子:假设我们有一个全局变量n=0,创建20个线程,每个线程都执行n+=1,结果应该是20.但是会有这样一个问题:在执行第一个线程时,如果到了规定时间这个线程还没有执行完, 那么它只能暂时退出,先让其他的线程来执行.这样的话第一个线程没有执行完,那么此时n依然等于0.那么第二个线程拿到的n依然是0.这时候就会出现错误,因为这样的结果是第一个线程执行结果为1,第二个线程执行的结果也为1,最终20个线程执行的结果就是19,这样就会出现错误.
我们来看下面这一段程序:
import threading
import time
start_time = time.time()
num = 0
def func():
global num
for i in range(100000):
num += 1
thread_1 = threading.Thread(target=func)
thread_2 = threading.Thread(target=func)
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
print(num)
end_time = time.time()
print('cost time {}s'.format((end_time-start_time)))
我们来分析一下这段代码:
代码中定义了一个函数func,作用是对循环100000次num+1,然后定义了两个子线程,这样的话这段程序的结果就是200000,但是通过运行程序发现结果并不是200000,而且多运行几次,会发现每次的结果都不一样.至于具体原理,我们上边已经讲了.
下面是运行结果:
181710
cost time 0.03139781951904297s
2.什么是线程锁
线程锁的意思是给每一个线程加上锁,当这个线程执行完成后才释放锁,下一个线程才能执行,这样就可以保证数据的安全准确,但是这样做就失去了并行的效果,所有的线程都是串行了.
线程锁使用方式:
lock = threading.LOCK() # 创建LOCK类实例
lock.acquire() # 获取锁
lock.release() # 释放锁,只有一个线程将锁释放了,另一个线程才能执行.
3.具体用法
对于上面那个例子,我们加上线程锁:
import threading
import time
start_time = time.time()
threading_lock = threading.Lock()
num = 0
def func():
global num
for i in range(100000):
threading_lock.acquire() # 获得锁
num += 1
threading_lock.release() # 释放锁
thread_1 = threading.Thread(target=func)
thread_2 = threading.Thread(target=func)
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
print(num)
end_time = time.time()
print('cost time {}s'.format((end_time-start_time)))
加上锁以后再执行,发现结果是200000(运行了20次,每次都是200000),下面是运行结果:
200000
cost time 0.42098522186279297s
作为对比,我们在做这种数值计算时,不用多线程,直接让func函数执行两次:
import threading
import time
start_time = time.time()
threading_lock = threading.Lock()
num = 0
def func():
global num
for i in range(100000):
threading_lock.acquire() # 获得锁
num += 1
threading_lock.release() # 释放锁
func()
func()
print(num)
end_time = time.time()
print('cost time {}s'.format((end_time-start_time)))
执行结果:
200000
cost time 0.07037591934204102s
天哪,使用多线程的时间竟然比不适用多线程的时间要多将近6倍!!!
从这里我们也可以看出,多线程并不适合这种数值计算密集型的程序(即CPU操作密集型),但多线程对于I/O操作密集型的程序来说则是非常有用的.