python filelock_python多线程锁Lock和RLock

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步,使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,分别用来获取和释放锁

Lock和RLock有什么区别呢?很多教程都只提到RLock可以多次acquire和release,举的例子就是类似这种:

import threading

rlock=threading.RLock()

def foo():

rlock.acquire()

rlock.acquire() # 可以多次获得锁

print('multi-acquire')

rlock.release()

rlock.acquire() # acquire几次锁就要release 几次

t=threading.Thread(target=foo)

t.start()

t.join()

#输出

multi-acquire

看完了还是一头雾水,虽然知道了RLock可以多次获取释放,但有什么用呢?获取一次锁就行了为啥还要多次获取呢? 下面就举例说一下这个RLock可以多次获取锁的好处

假如在多线程环境下我们要对一个变量num进行加一操作,并且加一操作前我们需要检查这个变量是不是负值

import threading

lock=threading.Lock()

num=1

def check(): #检查变量是否小于零

global num

lock.acquire()

if num<0:

print('num<0')

else:

print('num>1')

lock.release()

def add(): # 对变量进行+1操作

global num

lock.acquire()

check() #加一操作前检查num的值是否小于零

num += 1

lock.release()

t=threading.Thread(target=add)

t.start()

t.join()

上面的这段代码会发生死锁情况,因为在add函数里先通过lock.acquire()获取了锁,然后调用check函数的时候,check函数里又在获取锁,这就造成死锁情况。这种情况也就是在一个加锁的操作里调用另一个加锁的方法,而且加的是同一把锁,就会发生死锁。解决方法很简单,就是把Lock换成RLock就行了

让我们在举一个实用点的例子

现在要使用递归方法计算一个数的累乘,并要求加锁实现计算过程中不会被其他线程干扰

from threading import Lock

lock = Lock()

def factorial(n):

assert n > 0

if n == 1:

return 1

with lock:

out = n * factorial(n - 1)

return out

print(factorial(3)) #发生死锁,无法执行

上面递归的函数里使用with 语句简化了锁的acquire和release 写法。

在with语句里又递归调用了factorial函数本身,这就会发生再次请求锁的情况,所以第一次递归的时候就发生了死锁,解决的方法还是一样,把Lock换成RLock即可

上面的例子说明了多次获取锁的实际用途,其实RLock和Lock的区别还有另一点,就是:

Lock获取的锁可以被其他任何线程直接释放

RLock获取的锁只有获取这个锁的线程自己才能释放

看下面的例子:

import threading

import time

lock = threading.Lock()

def a():

lock.acquire()

time.sleep(3)

lock.release()

def b():

lock.release()

print('lock released')

t1=threading.Thread(target=a)

t2=threading.Thread(target=b)

t1.start()

t2.start()

t1.join()

t2.join()

#输出:

lock released

Exception in thread Thread-1:

Traceback (most recent call last):

File "D:\python3.6\lib\threading.py", line 916, in _bootstrap_inner

self.run()

File "D:\python3.6\lib\threading.py", line 864, in run

self._target(*self._args, **self._kwargs)

File "C:/Users/test/Desktop/test.py", line 9, in a

lock.release()

RuntimeError: release unlocked lock

t1线程在函数a里面获取了锁,然后sleep 3秒钟,这时候t2线程的b函数在没有获取锁的情况下直接就释放的锁,然后执行print('lock released')打印输出,等3秒后线程t1醒来后再试图释放一个已经被释放的锁的时候,就会报RuntimeError: release unlocked lock 错了,说明t2线程可以获取t1线程的lock锁

如果把上面的锁改成RLock,输出会变成这样

Exception in thread Thread-2:

Traceback (most recent call last):

File "D:\python3.6\lib\threading.py", line 916, in _bootstrap_inner

self.run()

File "D:\python3.6\lib\threading.py", line 864, in run

self._target(*self._args, **self._kwargs)

File "C:/Users/test/Desktop/test.py", line 13, in b

lock.release()

RuntimeError: cannot release un-acquired lock

报错信息:无法释放一个没有获取到的锁, 说明t2 线程的b函数里,无法获取t1线程获取的rlock锁

你可能感兴趣的:(python,filelock)