QA测试开发工程师面试题满分问答22: (干货)为什么要加锁Lock,举个例子说说

news2024/10/7 8:31:26

加锁原因

下面代码会有什么问题?

import threading
import requests
from queue import Queue

def make_request(url, params, results_queue):
    response = requests.get(url, params=params)
    result = {
        'url': url,
        'params': params,
        'response': response.text
    }
    results_queue.put(result)

# 定义接口 URL
url = "https://api.example.com/endpoint"

# 定义要传递给接口的不同参数列表
params_list = [
    {'param1': 'value1'},
    {'param2': 'value2'},
    {'param3': 'value3'}
]

# 创建线程列表和结果队列
threads = []
results_queue = Queue()

# 遍历参数列表,为每个参数创建一个线程并启动
for params in params_list:
    thread = threading.Thread(target=make_request, args=(url, params, results_queue))
    threads.append(thread)
    thread.start()

# 等待所有线程执行完毕
for thread in threads:
    thread.join()

# 从结果队列中获取结果
results = []
while not results_queue.empty():
    result = results_queue.get()
    results.append(result)

# 打印结果
for result in results:
    print(f"URL: {result['url']}, Params: {result['params']}, Response: {result['response']}")

results_queue.put(result),这里会有子线程并发写进同一个共享变量中,可能会数据不一致

加锁Lock

加个lock避免共享变量读写冲突,demo

import threading
import requests
from queue import Queue

def get_GTP4_result(url, results_dict):
    # 省略部分代码

    results_dict[url] = response

# 定义要传递给接口的不同参数列表
url_list = [
    "http://1.jpg",
    "https://2.jpg"
]

# 创建线程列表和结果字典
threads, results_dict = [], {}

# 创建锁对象
lock = threading.Lock()

# 定义线程函数
def thread_function(url):
    response = get_GTP4_result(url)
    with lock:
        results_dict[url] = response

# 遍历参数列表,为每个参数创建一个线程并启动
for url in url_list:
    thread = threading.Thread(target=thread_function, args=(url,))
    threads.append(thread)
    thread.start()

# 等待所有线程执行完毕
for thread in threads:
    thread.join()

# 按照URL的顺序获取结果
results = [results_dict[url] for url in url_list]

# 打印结果
for result in results:
    print(f"Response: {result}")

加lock,具体有哪些好处

加锁(Lock)用于保护共享资源的访问,确保线程安全性。在多线程环境中,多个线程同时访问和修改共享变量可能导致数据竞争和不一致的结果。加锁可以解决这个问题,并提供以下好处:

  1. 数据一致性:加锁可以防止多个线程同时对共享变量进行读写操作,从而避免数据的不一致性。当一个线程获得锁后,其他线程需要等待锁的释放,确保每次只有一个线程能够修改共享变量。

  2. 线程安全性:通过加锁,可以保证对共享变量的操作是线程安全的。线程安全意味着多个线程并发地访问共享资源时,不会出现竞争条件、数据损坏或不一致的情况。

  3. 避免竞争条件:通过使用锁,可以防止多个线程同时执行对共享变量的修改操作,从而避免竞争条件的发生。竞争条件是指多个线程在执行过程中产生的不确定性结果,可能导致程序的错误行为。

  4. 保护临界区:加锁可以将一段代码标记为临界区,只允许一个线程进入执行。这样可以确保在该临界区内对共享变量的操作是原子的,不会受到其他线程的干扰。

  5. 同步线程执行顺序:使用锁可以控制多个线程的执行顺序,确保它们按照预期的顺序执行。通过在合适的地方加锁和释放锁,可以实现线程之间的同步和协调。

python的多线程如何加锁和释放锁,有几种方式

在 Python 中,可以使用 threading 模块提供的锁对象 Lock 来实现线程的加锁和释放锁。常用的加锁和释放锁的方法有以下几种:

  1. 使用 Lock 对象的 acquire() 和 release() 方法:

    • acquire() 方法用于获取锁,如果锁已经被其他线程获取,则当前线程会被阻塞,直到锁被释放。
    • release() 方法用于释放锁,将锁的状态设置为可获取,允许其他线程获取该锁。
    import threading
    
    # 创建锁对象
    lock = threading.Lock()
    
    # 在需要加锁的代码块中使用锁
    lock.acquire()
    try:
        # 执行需要加锁的操作
        # ...
    finally:
        # 释放锁
        lock.release()
    
  2. 使用 with 语句简化锁的使用:
    Lock 对象也支持上下文管理器协议,可以使用 with 语句来自动获取和释放锁。

    import threading
    
    # 创建锁对象
    lock = threading.Lock()
    
    # 在需要加锁的代码块中使用锁
    with lock:
        # 执行需要加锁的操作
        # ...
    
  3. 使用 RLock 对象实现可重入锁:
    RLock 是 Lock 的子类,支持同一个线程多次获取锁而不会造成死锁。如果在一个线程中多次获取 Lock 对象,该线程会一直处于阻塞状态,因为它已经持有了该锁。而 RLock 对象允许同一个线程多次获取锁,并通过相同次数的释放操作来释放锁。

    import threading
    
    # 创建可重入锁对象
    rlock = threading.RLock()
    
    # 在需要加锁的代码块中使用可重入锁
    rlock.acquire()
    try:
        # 执行需要加锁的操作
        # ...
    finally:
        # 释放锁
        rlock.release()
    

这些方法都可以保证线程安全性,并避免多个线程同时访问共享资源。选择使用哪种方法取决于具体的需求和场景。通常情况下,推荐使用 with 语句来简化锁的使用,因为它可以自动处理锁的获取和释放,避免忘记释放锁的情况发生。如果需要支持同一个线程多次获取锁,可以使用 RLock 对象。

python多线程还有没有其他锁呢

除了常用的 Lock 和 RLock,Python 的 threading 模块还提供了其他类型的锁,用于不同的场景和需求。以下是一些常见的锁类型:

  1. Semaphore(信号量):信号量是一种允许多个线程同时访问临界区的锁机制。它维护一个内部计数器,线程在进入临界区之前必须先获得信号量的许可,每次许可获取后计数器减一。当计数器为零时,其他线程需要等待。可以使用 Semaphore 对象的 acquire() 和 release() 方法来控制许可的获取和释放。

    import threading
    
    # 创建信号量对象,指定许可的数量
    semaphore = threading.Semaphore(2)  # 允许两个线程同时访问临界区
    
    # 在需要访问临界区的代码块中使用信号量
    semaphore.acquire()
    try:
        # 执行需要访问的临界区操作
        # ...
    finally:
        # 释放信号量
        semaphore.release()
    
  2. Event(事件):事件是一种线程间的通信机制,用于一个或多个线程等待某个事件的发生。它有两种状态:已设置和未设置。线程可以等待事件的设置,也可以通过设置事件来通知其他线程。Event 对象的 wait() 方法用于等待事件的设置,set() 方法用于设置事件,clear() 方法用于清除事件。

    import threading
    
    # 创建事件对象
    event = threading.Event()
    
    # 在等待事件发生的线程中使用事件
    event.wait()
    
    # 在设置事件的线程中使用事件
    event.set()
    
    # 在清除事件的线程中使用事件
    event.clear()
    
  3. Condition(条件):条件是一种复杂的锁机制,用于线程间的协调和通信。它提供了一个线程可以等待的条件,并且可以通过 wait()notify() 和 notifyAll() 方法来实现线程间的协调。Condition 对象基于底层的 Lock 对象来提供线程安全性。

    import threading
    
    # 创建条件对象
    condition = threading.Condition()
    
    # 在等待条件满足的线程中使用条件
    condition.wait()
    
    # 在满足条件的线程中使用条件
    condition.notify()
    
    # 在满足条件的线程中使用条件,通知所有等待的线程
    condition.notifyAll()
    

这些锁类型提供了更多的灵活性和功能,可以根据具体的需求选择适合的锁机制。在多线程编程中,根据线程间的协作和通信需求来选择合适的锁类型非常重要,以确保线程安全和正确的并发行为。

   三段头部互联网大厂测开经历,辅导过25+同学入职大厂,【简历优化】、【就业指导】、【模拟/辅导面试】一对一指导

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1660338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

官方文档k8s1.30安装部署高可用集群,kubeadm安装Kubernetes1.30最新版本

文章目录 节点架构一、准备开始(每一台机器都执行)1️⃣ 检查所需端口(可以直接关闭防火墙放开所有端口)端口和协议控制面工作节点 关闭防火墙关闭 SELinux 2️⃣ 安装containerd容器containerd部署containerd切换为国内源 3️⃣ 设置/etc/hosts 二、安装 kubeadm、kubelet 和 …

4大遥感软件!遥感影像解译!ArcGIS+ENVI+Erdas+eCognition

包含ArcGISENVIErdaseCognition 4大软件4个课程的遥感影像大综合,一个课程套餐让你学遍常用的遥感影像处分析等。 课后答疑 学习群答疑 实战驱动 课件、课程操作数据 福利数据包 课程概述 总共146(18454538)课时 点下如下课程卡学习&…

5.07 Pneumonia Detection in Chest X-Rays using Neural Networks

肺炎诊断是一个耗时的过程,需要高技能的专业人员分析胸部X光片chest X-ray (CXR),并通过临床病史、生命体征和实验室检查确认诊断。 它可以帮助医生确定肺部感染的程度和位置。呼吸道疾病在 X 光片上表现为一处膨胀的不透明区域。然而,由于不…

浅谈操作系统中的重要概念——线程(3)——设计模式

文章目录 一、什么是设计模式?二、单例模式2.1、饿汉模式2.2、懒汉模式2.3、多线程情况下调用 饿汉模式与懒汉模式 谁是安全的??(重点) 三、工厂模式3.1、什么是工厂模式?3.1.1、构造方法存在的缺陷3.1.1.1…

初步了解Kubernetes

目录 1. K8S概述 1.1 K8S是什么 1.2 作用 1.3 由来 1.4 含义 1.5 相关网站 2. 为什么要用K8S 3. K8S解决的问题 4. K8S的特性 5. Kubernetes集群架构与组件 6. 核心组件 6.1 Master组件 6.1.1 Kube-apiserver 6.1.2 Kube-controller-manager 6.1.3 kube-schedul…

基于springboot实现智慧图书管理系统项目【项目源码+论文说明】

基于springboot实现智慧图书管理系统演示 摘要 如今社会上各行各业,都在用属于自己专用的软件来进行工作,互联网发展到这个时候,人们已经发现离不开了互联网。互联网的发展,离不开一些新的技术,而新技术的产生往往是为…

企业数据有什么价值?

在当下的数字经济时代,数据已上升为国家重要的基础性战略资源,加快建设数字中国、网络强国这一蓝图的实现,离不开数据要素的支撑。数据作为新型生产要素,具有非消耗性、非竞争性等特征,为突破传统生产要素的增长约束提…

SolidWorks2024 正版软件报价

随着科技的飞速发展,三维设计软件在制造业、工程领域的应用越来越广泛。SolidWorks作为一款三维CAD设计软件,其每一代的更新都受到广大用户的热烈关注。今日,我们将深入探讨SolidWorks 2024正版软件的报价及其所蕴含的功能价值。 首先&#…

光检测器——光纤通信学习笔记七

光检测器 光检测器的基本介绍 作用:把接受到的光信号转换成电信号 光接收器的灵敏度、光源的发光功率和光纤的损耗三者决定了光纤通信的传输距离; 光电二极管 光电转换的基本原理 之前提到,PN结由于内部载流子的扩散运动形成了内部电场&…

uni-app(五):原生插件打包并使用(Android)

原生插件打包并使用 解决Gradle不显示命令问题解决方法 运行打包查看打包好的包引入到uni-app项目中编写配置文件TestModuleTestComponent 制作基座并运行 解决Gradle不显示命令问题 解决方法 运行打包 查看打包好的包 引入到uni-app项目中 编写配置文件 TestModule {"n…

postgresql主从复制

用vmware 搭建的两台虚拟机 操作系统:Ubuntu 24.04 Server版 数据库:postgresql 16.2 主库:192.168.2.11 从库:192.168.2.12 如果遇到网络无法上网,可参考一下 Vmware 搭建的Ubuntu 24.04 网络配置-CSDN博客 1.两…

错误处理机制——vba(vb.net)

程序出现错误时可采用如下错误处理机制:出错时跳到标签处,判断错误类型修正错误,重新返回正确标签处,继续运行程序。 代码如下: Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click…

CLI举例:配置HTTP服务器的负载均衡

CLI举例:配置HTTP服务器的负载均衡 本举例介绍了如何配置HTTP服务器的负载均衡。 组网需求 如图1所示,企业有三台Web服务器Server1、Server2和Server3,且这三台服务器的硬件性能顺次降低,Server1性能是Server2的两倍、Server2性能…

苹果新品发布会速览:iPad革新遇市场挑战 | 百能云芯

北京时间5月7日晚,苹果以“放飞吧”为主题,举办了一场不到40分钟的线上新品发布会。在这场发布会上,iPad产品线成为了焦点,M4芯片和OLED技术的融入更是引起了广泛关注。 iPad新篇章:技术革新与市场竞争 时隔18个月&…

Linux环境下部署vsftp+mysql用户认证

安装mysql(不要使用红帽的RPM版的mysql) 使用编译或静态库安装mysql 1、编译安装pam_mysql 下载软件: http://downloads.sourceforge.net/project/pam-mysql/pam-mysql/0.7RC1/pam_mysql-0.7RC1.tar.gz?rhttp%3A%2F%2Fsourceforge.net%2Fprojects%2Fpam-mysql%2F…

【回溯算法】【Python实现】符号三角形问题

文章目录 [toc]问题描述回溯法时间复杂性Python实现 问题描述 下图是由 14 14 14个“ ”和 14 14 14个“ − - −”组成的符号三角形, 2 2 2个同号下面都是” “, 2 2 2个异号下面都是“ − - −” 在一般情况下,符号三角形的第一行有 n…

MySQL慢查询SQL优化

一、慢查询日志 描述:通过慢查询日志等定位那些执行效率较低的SQL语句 查看 # 慢查询是否开启 show variables like slow_query_log%; # 慢查询超时时间 show variables like long_query_time%;执行SQL 开启慢查询日志 set global slow_query_log ON;设置慢查…

python数据分析——数据的选择和运算

数据的选择和运算 前言一、数据选择NumPy的数据选择一维数组元素提取示例 多维数组行列选择、区域选择示例 花式索引与布尔值索引布尔索引示例一示例二 花式索引示例一示例二 Pandas数据选择Series数据获取DataFrame数据获取列索引取值示例一示例二 取行方式示例loc() 方法示例…

一篇文章,系统性聊聊Java注解

你好! 这类系统性聊聊***知识点的文章,是希望给大家带来对某个技术的全貌认识,如果大家喜欢,后续可以陆续更新此系列 下面,开始今天的分享 在之前,我们已经分享过注解相关的三个面试题, 今天的…

【原创教程】步进MC_HOME回原点模式

我们所用软件:西门子TIA Portal V16编程软件 我们所用硬件:S7-1200系列:CPU1212C;雷赛科技DM542驱动器;西门子TP900 comfort触摸屏 我们的硬件接线 MC_HOME的模式: 一般情况下,西门子PLC的运动控制在使能绝对位置定位之前必须执行“回原点”或是“寻找参考点”。 Pos…