迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Python >

Python 中的线程锁

作者:迹忆客 最近更新:2023/02/20 浏览次数:

本教程将讨论在 Python 中使用线程锁的不同方法。


Python 中的竞争条件

竞争条件是当多个线程尝试修改同一个共享变量时出现的问题。所有线程同时从共享变量中读取相同的值。然后,所有线程尝试修改共享变量的值。但是,该变量最终只会存储最后一个线程的值,因为它会覆盖前一个线程写入的值。从这个意义上说,所有线程之间存在竞争,以查看最终哪个线程修改了变量的值。以下代码中的示例演示了这种现象。

from threading import Thread

counter = 0

def increase(by):
    global counter
    local_counter = counter
    local_counter += by
    counter = local_counter
    print(f'counter={counter}')

t1 = Thread(target=increase, args=(10,))
t2 = Thread(target=increase, args=(20,))

t1.start()
t2.start()

t1.join()
t2.join()

print(f'The final counter is {counter}')

输出:

counter=10
counter=20
The final counter is 20

Python 中的竞争条件

我们有一个全局共享变量 counter = 0 和两个线程 t1 和 t2。线程 t1 尝试将 counter 的值增加 10,线程 t2 尝试将 counter 的值增加 20。在上面的代码中,我们同时运行两个线程并尝试修改值计数器。根据上述逻辑,counter 的最终值应该是 30。但是,由于竞争条件,counter 要么是 10,要么是 20。


Python 中的线程锁

线程锁用于防止竞争条件。线程锁在被一个线程使用时锁定对共享变量的访问,以便任何其他线程无法访问它,然后在线程不使用共享变量时移除锁,以便其他线程可以使用该变量进行处理。threading 模块中的 Lock class 用于在 Python 中创建线程锁。acquire() 方法用于锁定对共享变量的访问,而 release() 方法用于解锁锁定。如果在未锁定的锁上使用 release() 方法会引发 RuntimeError 异常。

from threading import Thread, Lock

counter = 0


def increase(by, lock):
    global counter

    lock.acquire()

    local_counter = counter
    local_counter += by
    counter = local_counter
    print(f'counter={counter}')

    lock.release()


lock = Lock()

t1 = Thread(target=increase, args=(10, lock))
t2 = Thread(target=increase, args=(20, lock))

t1.start()
t2.start()

t1.join()
t2.join()

print(f'The final counter is {counter}')

输出:

counter=10
counter=30
The final counter is 30

Python 中的线程锁

我们创建了一个全局共享变量 counter=0 和两个线程 t1 和 t2。两个线程都针对相同的 increase() 函数。increase(by, lock) 函数有两个参数。第一个参数是它将增加 counter 的数量,第二个参数是 Lock 类的实例。除了前面的声明,我们还在 Python 的 threading 模块中创建了一个 Lock 类的实例 lock。increase(by, lock) 函数中的这个 lock 参数使用 lock.acquire() 函数锁定对 counter 变量的访问,同时它被任何线程修改,并使用 lock 解锁锁定。release() 函数,当一个线程修改了 counter 变量。线程 t1 将 counter 的值增加 10,线程 t2 将 counter 的值增加 20。 由于线程锁定,不会发生竞争条件,最终 counter 的值为 30。


在 Python 中使用 with lock: 的线程锁

前一种方法的问题在于,当一个线程完成处理时,我们必须小心地解锁每个锁定的变量。如果没有正确完成,我们的共享变量将只会被第一个线程访问,而其他线程将无法访问共享变量。这个问题可以通过使用上下文管理来避免。我们可以使用 with lock: 并将我们所有的关键代码放在这个块中。这是防止竞争条件的更简单的方法。以下代码片段显示了使用 with lock: 来防止 Python 中的竞争条件。

from threading import Thread, Lock

counter = 0

def increase(by, lock):
    global counter

    with lock:
        local_counter = counter
        local_counter += by
        counter = local_counter
    print(f'counter={counter}')

lock = Lock()

t1 = Thread(target=increase, args=(10, lock))
t2 = Thread(target=increase, args=(20, lock))

t1.start()
t2.start()

t1.join()
t2.join()

print(f'The final counter is {counter}')

输出:

counter=10
counter=30
The final counter is 30

在 Python 中使用 with lock 的线程锁

我们将增加 counter 的代码放在 with lock: 块中。线程 t1 将 counter 的值增加 10,线程 t2 将 counter 的值增加 20。没有发生竞争条件,counter 的最终值为 30。此外,我们不需要担心解锁线程锁。

两种方法都完美地完成了它们的工作,即两种方法都可以防止竞争条件的发生,但是第二种方法远远优于第一种,因为它可以避免我们为处理线程锁的锁定和解锁而头疼。与第一种方法相比,它编写起来也更简洁,更易于阅读。


注: 本文转载自:delftstack 。对于文中示例已都进行过运行。如遇到错误代码会进行相应的修改,修改正确之后才会在文中发布。如大家在运行示例中发现有代码错误的,请及时告知。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Python for 循环中的下一项

发布时间:2023/04/26 浏览次数:179 分类:Python

本文讨论了 Python 中的 for 循环以及如何通过使用 for 循环和示例来跳过列表的第一个元素。

Python While 循环用户输入

发布时间:2023/04/26 浏览次数:148 分类:Python

我们可以在 while 循环中使用 input() 函数来输入数据,直到在 Python 中满足某个条件。

Python 中的整数规划

发布时间:2023/04/26 浏览次数:193 分类:Python

本文介绍了整数规划和可用于解决混合整数规划问题的 Python 工具。

在 Python 中将整数转换为罗马数字

发布时间:2023/04/26 浏览次数:87 分类:Python

本篇文章将介绍在 Python 中将整数转换为罗马数字。以下是一个 Python 程序的实现,它将给定的整数转换为其等效的罗马数字。

在 Python 中将罗马数字转换为整数

发布时间:2023/04/26 浏览次数:144 分类:Python

本文讨论如何在 Python 中将罗马数字转换为整数。 我们将使用 Python if 语句来执行此操作。 我们还将探讨在 Python 中将罗马数字更改为整数的更多方法。

在 Python 中读取 gzip 文件

发布时间:2023/04/26 浏览次数:70 分类:Python

本篇文章强调了压缩文件的重要性,并演示了如何在 Python 中使用 gzip 进行压缩和解压缩。

在 Python 中锁定文件

发布时间:2023/04/26 浏览次数:141 分类:Python

本文解释了为什么在 Python 中锁定文件很重要。 这讨论了当两个进程在没有锁的情况下与共享资源交互时会发生什么的示例,为什么在放置锁之前知道文件状态很重要,等等

在 Python 中将 PDF 转换为文本

发布时间:2023/04/26 浏览次数:196 分类:Python

在本教程中,我们将学习如何使用 Python 使用 PyPDF2、Aspose 和 PDFminer 将 PDF 文档转换为文本文件。

在 Python 中创建临时文件

发布时间:2023/04/26 浏览次数:53 分类:Python

本文讲解了tempfile库函数的四个子函数:TemporaryFile、NamedTemporaryFile、mkstemp、TemporaryDirectory。 每个部分都提供了适当的程序,以简化对概念的理解。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便