浅谈Python的锁机制

一、锁(Lock)机制

  Python中为了解决多线程的安全问题, threading 模块引入了锁(Lock)。当多个线程需要对共享资源进行操作时,通常这些资源都是可变对象,因此需要额外的方法来保证其线程安全。threading 模块提供了 Lock 和 RLock 两个类,它们都提供了如下两个方法来加锁和释放锁,这两个方法必须成对出现:

acquire(blocking=True, timeout=-1):请求对 Lock 或 RLock 加锁,其中 timeout 参数指定加锁多少秒。
release():释放锁。

Lock 和 RLock 的区别如下:

  Lock:是一个基本的锁对象,每次只能锁定一次,其余的锁请求,需等待锁释放后才能获取。

  RLock:代表可重入锁(Reentrant Lock)。对于可重入锁,在同一个线程中可以对它进行多次锁定,也可以多次释放。如果使用 RLock,那么 acquire() 和 release() 方法必须成对出现。如果调用了 n 次 acquire() 加锁,则必须调用 n 次 release() 才能释放锁。
  由此可见,RLock 锁具有可重入性。也就是说,同一个线程可以对已被加锁的 RLock 锁再次加锁,RLock 对象会维持一个计数器来追踪 acquire() 方法的嵌套调用,线程在每次调用 acquire() 加锁后,都必须显式调用 release() 方法来释放锁。所以,一段被锁保护的方法可以调用另一个被相同锁保护的方法。
  Lock 是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程在开始访问共享资源之前应先请求获得 Lock 对象。当对共享资源访问完成后,程序释放对 Lock 对象的锁定。

二、with的用法

  Python中一般在文件,多线程锁(threading.Lock)等操作时最常用的就是使用with上下文管理器,这样会让代码的可读性更强而且错误更少,创建上下文管理实际就是创建一个类,添加__enter__和__exit__方法。
  Python标准库还提供了更加易用的上下文管理器工具模块contextlib,它是通过生成器实现的,这样就不需要再创建类以及__enter__和__exit__这两个方法。
  外部使用contextmanager将该类包装成为一个上下文管理器,这样既可以调用类中的方法,又可以在执行核心代码前后再执行一些相关的语句。yield关键词把上下文分割成两部分,这样做的好处在于,我们就可以在执行真正的核心代码之前可以执行一部分代码,然后在执行完毕后,又可以执行一部分代码,这种场景在openstack中还是很常见的。
举个简单例子:

from contextlib import contextmanager

@contextmanager
def python_book():
	print('《', end='')
	yield
	print('》', end='')

with python_book():
	# 业务核心代码
	print('流畅的Python', end='')
# 结果: 《流畅的Python》

你可能感兴趣的:(python)