Python中Lock和Rlock对象之间的区别

2025年1月5日 | 阅读8分钟

引言

在本教程中,我们将学习 Python 中 Lock 和 Rlock 对象之间的区别。线程是进程可以调度的执行点。它也是操作系统 (OS) 中可完成的最小工作量。简而言之,线程是一系列指令。它可以独立于程序中的其他代码执行。为了简单起见,您可以将线程视为一个进程。Lock 对象是一种简单的互斥机制。它允许多个线程获取和释放锁,但同一时间只有一个线程可以持有锁。当一个线程尝试获取一个已经被另一个线程持有的锁时,它将被阻塞,直到锁可用为止。这确保了锁保护了代码的关键部分,使其一次只能由一个线程执行。

另一方面,RLock 对象通过提供重入性或递归锁定来扩展 Lock 的功能。重入性允许已经持有锁的线程在不引起死锁的情况下重新获取锁。当调用或代码段需要多个锁定级别时,尤其如此。使用 RLock 对象,一个线程可以多次获取锁,并且必须同时释放锁才能让另一个线程使用它。这确保了锁在所有记录完成之前一直被持有。

什么是锁对象?

这些是 Python 中基本的同步原语。锁有两种状态:锁定和解锁。锁是 threading 模块中的一个类,其对象以锁定状态创建,并具有 acquire() 和 release() 两个主要方法。当调用 acquire() 方法时,它会阻止 Lock 的执行,并防止它执行,直到另一个线程调用 release() 方法将其设置为锁定状态。锁有助于我们更好地访问程序中的共享资源,以防止数据损坏。

关于 Lock 对象的一个重要注意事项是它们不支持重入。重入性是指线程能够多次获取同一锁而不会导致死锁的能力。对于 Lock,如果已经持有锁的执行线程尝试重新获取锁,这将导致系统挂起,并且执行线程将无法完成,从而导致程序挂起。因此,Lock 对象适用于不需要重入行为的情况,例如简单的连接或没有嵌套函数调用的情况。

程序代码

在此,我们提供一个 Python 中锁对象的程序代码,如下所示:

输出

在上面的程序代码中,lock_obj 是一个锁对象,全局变量“a”是一个共享资源。sum_of_One()、sum_of_Two() 和 sum_of_Three() 函数遵循线程。在 sum_of_One() 函数中,加 1,然后释放“a”。然后,在 sum_of_Two() 函数中,先锁定“a”变量,然后加 2,然后释放。之后,在 sum_of_Three() 函数中,先锁定“a”变量,然后加 3,然后释放。sum_of_One()、sum_of_Two() 和 sum_of_Three() 函数不能同时访问共享资源。现在,我们编译并运行上面的代码,找出我们共享的资源的最终值。输出如下:

The value is: 6

什么是 Rlock 对象?

RLock 对象是“可重入锁”的缩写,是 Lock 对象的一个扩展,它解决了非可重入锁的局限性。它支持重入,允许线程在不引起死锁的情况下多次获取锁。RLock 对象的主要特性是控制锁获取的能力。这意味着线程可以在嵌套线程中多次获取锁。每次获取都必须释放相应的次数,锁才能被释放。这种行为在需要多级锁定的嵌套函数调用或代码段的情况下尤其有用。

RLock 对象提供了 acquire() 和 release() 方法,这与 lock 对象相同,使其易于使用。此外,它还提供了两个额外的方法,如带参数 block 的 acquire() 和带参数 counting 的 release()。阻塞的 acquire() 方法允许对锁的获取进行详细控制。当设置为 Block=False 时,线程可以尝试获取锁,但如果另一个线程持有锁,该线程将不会被阻塞。这允许线程在锁不可立即获得时执行其他任务或完成其他代码。

release() 方法包含一个计数器,将在指定的时间释放锁。这在线程需要释放多个锁,或者获取和释放次数可能动态变化的情况下非常有用。

程序代码

在此,我们提供一个 Python 中 Rlock 对象的程序代码,如下所示:

输出

在此,程序中的线程不一定会被阻止访问共享资源。我们需要为 RLock 对象锁的每次 acquire() 调用一次 release()。现在,我们编译并运行上面的代码,找出我们共享的资源的最终值。输出如下:

The value is: 10

程序代码

这里我们提供一个程序代码,展示如何在 Python 中同时使用 Lock 和 RLlock 对象。代码现在如下所示:

输出

在上面的代码中,我们有一个共享资源(shared_resource),多个线程正在访问它。increment_lock() 函数演示了如何使用锁来访问提供者中增加的关键部分。同样,Increment_rlock() 函数通过允许递归锁获取和释放来指定 RLlock 对象的使用。现在,我们编译并运行上面的代码,找出我们共享的资源的最终值。输出如下:

The value of sharing resource using Lock is: 6
The value of sharing resource using RLock is: 12

在 Lock 和 Rlock 之间如何选择?

在决定是在并发程序中使用 Lock 还是 RLlock 时,请考虑以下提示,如下所示:

  1. 仅当您需要简单的互斥机制且不需要重入性时,才使用 Lock。Lock 是轻量级的,适用于没有嵌套函数调用或多级锁定的简单同步场景。
  2. 当您有需要多级锁定的嵌套函数调用或代码片段时,请使用 RLock。在这种情况下,RLock 通过允许线程反复获取锁来确保真正的同步。它支持重入行为并防止在反复获取锁时发生冲突。

Lock 和 Rlock 之间的区别。

Lock 和 Rlock 之间存在一些区别,如下所示:

ObjectLockRlock
定义线程不能撤销锁对象,除非访问共享资源的线程释放了它。每个线程可以多次检索 Rlock 对象。
执行时间锁对象的执行速度比 Rlock 对象快。RLock 对象的执行速度比 Lock 对象慢。
对象释放线程释放锁对象。RLock 对象仅由获取它的线程释放。
对象所有者锁对象不属于任何人。线程拥有 Rlock 对象。

结论

在本教程中,我们将学习 Python 中 Lock 和 Rlock 对象之间的区别。在 Python 并发编程中,Lock 和 RLock 对象协同工作以控制对共享资源的访问。虽然锁提供了互斥,但 RLlock 产品通过提供重入支持扩展了其功能。理解这些组件之间的差异对于编写健壮且线程安全的 कोड 非常重要。