您的位置:

16. Python 中的锁对象——线程同步

Python 中的锁对象——线程同步

更新:

在多线程中,当多个线程同时处理一个共享资源(如文件)时(向文件中读写数据),为了避免并发修改错误(多个线程访问同一资源导致数据不一致),使用了某种锁定机制,当一个线程访问一个资源时,它会锁定该资源,直到它释放该锁定,其他线程都不能访问同一资源。


锁对象:Python 多线程

在 Python 的threading模块中,为了高效多线程,使用了一个原语锁。这个锁帮助我们同步两个或多个线程。锁类可能提供了 Python 中最简单的同步原语。

原始锁可以有两种状态:锁定或解锁,并且最初是在我们初始化 lock 对象时在解锁状态下创建的。它有两种基本方法,acquire()release()

以下是创建锁对象的基本语法:

import threading

threading.Lock()

锁对象使用两种方法,它们是:

acquire(blocking=True, timeout=-1)方法

此方法用于获取锁。当它在没有参数的情况下被调用时,它会一直阻塞,直到锁被解锁。

该方法可以采用 2 个可选参数,它们是:

  1. 阻塞标志,如果该锁已经被某个其他线程获得,则该标志如果作为False发送,将不会阻塞该线程,并将作为结果返回False。如果您将该阻塞标志的值提供为True,那么如果其他线程持有锁,调用线程将被阻塞,一旦锁被释放,那么您的线程将获得锁并返回True
  2. timeout 参数用于提供一个正浮点值,该值指定如果其他线程正在持有锁,调用线程将被阻塞的秒数。默认值为 -1 表示如果线程不能立即获得锁,它将被无限期阻塞。

release()方法

它用于释放获取的锁。如果锁被锁定,这个方法会将其重置为解锁状态,然后返回。此外,该方法可以从任何线程调用。

当调用此方法时,已经等待获取锁的线程中的一个被允许持有锁。

此外,如果在未锁定的锁上调用它,它会抛出RuntimeError


是时候举个例子了!

下面我们有一个简单的 python 程序,其中我们有一个类SharedCounter,它将作为线程之间的共享资源。

我们有一个task方法,我们称之为increment()方法。由于多个线程将访问同一个计数器并增加其值,因此存在并发修改的可能性,这可能导致counter的值不一致。

请始终从上面的代码中获取:

  1. 当一个线程使用acquire()方法获取锁,然后访问一个资源时,如果在访问资源的过程中出现了一些错误,会怎么样?在这种情况下,没有其他线程能够访问该资源,因此我们必须访问try块内的资源。在finally区块内部,我们可以调用release()方法来重新锁定。
  2. 尝试注释第 13 行和第 19 行的代码,并尝试多次运行代码,有时您会看到代码会给出正确的输出,但有时您会看到不正确的counter值。