8.同步锁lock
在以下函数中,如果想要将参数c减到0,函数需要执行100次
def a(): global c c-=1 c=100
这样太慢,100次函数执行得出结果太慢,就可以同时创建100个线程,1次减完,代码如下:
thread_list=[] for i in range(100): t=threading.Thread(Target=a) t.start() thread_list.append(t) for i in thread_list: t.join() print('执行结束,最后c=%d'%c)
以上代码是可以完成需求的,能够开出100个线程同时对数据减一
但是如果将函数a进行修改,如下:最终返回的数据就是跟预想的有偏差的,执行结果就不是0
def a(): global c time.sleep(4) c-=1 c=100 thread_list=[] for i in range(100): t=threading.Thread(target=a) t.start() thread_list.append(t) for i in thread_list: t.join() print('执行结束,最后c=%d'%c)
原因:
A线程首先获取全局变量c的值,如a=100,然后sleep函数时,a线程进入阻塞状态,cpu切换到其他线程,
同样要获取c的值,因为A线程还未执行到-1代码,c的值还是100,线程b获得的c值就是100,然后就进入阻塞状态
这时a线程执行完毕了,c的值变成99,A线程结束。然后b线程对c=100执行-1操作,c的值也是99。
这样100个线程下来,就会使最后的结果不是0
这种现象被称为线程不安全,线程不同步
解决方法:
1.join
加join后该线程的代码不执行完,不会执行其他线程,所写的多线程就变成串行执行,没有意义
2.加同步锁
方法 声明一个同步锁对象 l=threading.Lock()
同步锁的开头 l.acquire()
释放同步锁 l.release()
在同步锁中的程序全部串行执行,但是同步锁外的程序可以继续按照多线程执行,可以在数据处理的关键位置添加同步锁
def a(): global c l.acquire() time.sleep(0.05) c-=1 #给减一操作添加同步锁 l.release() c=100 thread_list=[] l=threading.Lock() for i in range(100): t=threading.Thread(target=a) t.start() thread_list.append(t) for i in thread_list: t.join() print('执行结束,最后c=%d'%c)
为什么已经给解释器加过GIL锁了,我们的程序还要添加同步锁?
GIL保证在同一时刻只有一个线程进入解释器中
同步锁是限制解释器来回切换线程,将解释器在某段时间内固定在一个线程,防止冲突。

浙公网安备 33010602011771号