树莓派4B学习笔记14:Python多线程编程_线程间的同步通信_(锁‘threading.Lock’)

今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi)

 本人所用树莓派4B 装载的系统与版本如下:

 版本可用命令 (lsb_release -a) 查询:

 Opencv 版本是4.5.1:

 今日学习树莓派与Python的多进程编程_线程间同步通信

 文章提供测试代码讲解,整体代码贴出、测试效果图

目录

建立简单的多线程:

创建一个新的线程对象:

 代码示例:

测试效果与解释:

join方法的使用:

线程间的同步与通信:

问题代码与说明:

竞态条件:

使用锁同步对共享资源的访问:

代码改进提示:

网上学习网址贴出:


建立简单的多线程:

创建一个新的线程对象:

threading.Thread 类用于创建一个新的线程对象。

这个类接受几个参数,其中最重要的是 targetargs

target

target 参数是一个可调用的对象(如函数或方法),当线程启动时,这个对象会被线程执行。在这个例子中,target 被设置为 counter 函数,所以新创建的线程会执行 counter 函数。

args

args 参数是一个元组,用于给 target 函数传递参数。在这个例子中,args 是一个只包含一个元素的元组,即字符串 "计数A"。当 t1 线程启动并调用 counter 函数时,它会传递这个字符串作为参数。

需要注意的是,由于 args 需要是一个元组,所以即使只传递一个参数,也需要用逗号 , 来表明它是一个元组(在只有一个元素的元组后面加上逗号是一个常见的约定)。

 代码示例:

以下代码简单示例了如何编写一个简单的多线程程序:

# -*- coding: utf-8 -*-  
import time  
import threading  
  
def counter(name):  
    for i in range(5):  
        print(name, i)  
        time.sleep(1)  

t1 = threading.Thread(target=counter, args=("计数A",))  
t2 = threading.Thread(target=counter, args=("计数B",))  
  
t1.start()  
t2.start() 
  
print("主线程完成")

测试效果与解释:

我们发现这个程序中一共三条线程:t1、t2、主线程

主线程因为只有一句prtint,因此在t1、t2计数第一次后就结束了

同时:t1、t2俩个线程是一起运行的

join方法的使用:

如果想主线程等待其余线程执行完,则可以使用join方法:

这样主线程就会在俩个子线程结束后才执行:

线程间的同步与通信:

问题代码与说明:

下面展示一段问题代码,该段代码有个全局变量N,程序试图通过多个线程对其进行加操作

从而达到快速加到某个值的效果:

# -*- coding: utf-8 -*-  
import time  
import threading  

# 定义一个全局变量,整数类型  
N=0

def Add(name):
    global N                  # 如果想在函数内部修改全局变量的值,需要使用global关键字  
    for i in range(10000):  
        N += 1                 # 使用 += 来递增全局变量

t1 = threading.Thread(target=Add, args=("累加1",))  
t2 = threading.Thread(target=Add, args=("累加2",))  
t3 = threading.Thread(target=Add, args=("累加3",))  
  
t1.start()  
t2.start() 
t3.start()   

t1.join() 
t2.join() 
t3.join()
 
print("主线程完成 N的最终值为:{}".format(N))

虽然我们发现这个操作结果是预期的30000,并未出现更改全局变量 N 冲突的情况,主要是因为线程间对 N 的增加操作是原子的(atomic)。在Python中,对于整数类型(int)和不可变类型(如元组、字符串等),在CPython实现中,简单的赋值和算术操作通常是原子的。

但是,请注意,这种情况并不意味着多线程环境下对全局变量的修改总是安全的。对于更复杂的操作或可变类型(如列表、字典等),多线程访问和修改可能会出现问题,例如数据竞争(data race)、死锁(deadlock)或条件竞争(condition race)。

竞态条件:

在以下给出的网址中的视频内就展示了对全局变量的非原子操作导致的加减输出混乱的情况

多线程编程:一次性搞懂线程同步机制_哔哩哔哩_bilibili

我们发现他的多线程程序并未累加全局变量到预期的值10万,而是运行出了六次不同的结果

使用锁同步对共享资源的访问:

threading.Lock

Lock 对象提供了一种方法来同步线程,以确保在任何时候只有一个线程可以访问共享资源。

下面是修改后的代码,其中添加了 Lock 来保护对全局变量 N 的访问:

# -*- coding: utf-8 -*-    
import time    
import threading    
  
# 定义一个全局变量,整数类型  
N = 0  
# 定义一个全局锁  
lock = threading.Lock()  
  
def Add(name):  
    global N, lock  
    for i in range(10000):  
        # 在修改N之前先获取锁  
        with lock:  
            N += 1                 # 使用 += 来递增全局变量  
  
t1 = threading.Thread(target=Add, args=("累加1",))    
t2 = threading.Thread(target=Add, args=("累加2",))    
t3 = threading.Thread(target=Add, args=("累加3",))    
    
t1.start()    
t2.start()   
t3.start()     
  
t1.join()   
t2.join()   
t3.join()  
   
print("主线程完成 N的最终值为:{}".format(N))

添加了一个名为 lockthreading.Lock 对象。

Add 函数中,我使用 with lock: 语句块来确保在修改 N 时锁是获取的。

这个 with 语句块会在进入时自动调用 lock.acquire() 来获取锁,并在退出时自动调用 lock.release() 来释放锁。

这样,在任何时候只有一个线程可以执行 N += 1 这行代码。

现在,即使你运行多个线程来同时修改 N,也不会出现数据不一致的问题,因为每个线程在修改 N 之前都会先获取锁,确保其他线程在此期间不会修改 N

运行效果展示:

代码改进提示:

但频繁地上锁解锁十分浪费资源,可以先定义一个局部变量代为运算,最后赋值给全局:

这样我们只需一次上锁与释放的操作就可以做到目标结果:

修改前繁琐的部分:

会进行高达10000次的:获取锁、释放锁的操作

修改的部分:

只进行了一次获取、释放锁的操作

整体代码:

# -*- coding: utf-8 -*-    
import time    
import threading    
  
# 定义一个全局变量,整数类型  
N = 0  
# 定义一个全局锁  
lock = threading.Lock()  
  
def Add(name):  
    global N, lock
    n=0
    for i in range(10000):  
        n+=1
    # 在修改N之前先获取锁  
    with lock:  
        N += n                 # 使用 += 来递增全局变量  
  
t1 = threading.Thread(target=Add, args=("累加1",))    
t2 = threading.Thread(target=Add, args=("累加2",))    
t3 = threading.Thread(target=Add, args=("累加3",))    
    
t1.start()
t2.start()
t3.start()
  
t1.join()
t2.join()
t3.join()  
   
print("主线程完成 N的最终值为:{}".format(N))

运行结果:

网上学习网址贴出:

100秒学会Python多线程threading_哔哩哔哩_bilibili

多线程编程:一次性搞懂线程同步机制_哔哩哔哩_bilibili

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Total Uninstall安装及卸载软件

Total Uninstall 的独特之处在于通过其安装的软件可以完整监控到新增或更改的注册表、文件、服务,可一键卸载。但常规的“360软件管家”无法做到以上内容。 借助该机制可用来无限刷新软件试用许可。 1.Total Uninstall 安装第三方软件 点击图中的“安装”&#xf…

NAND闪存原厂铠侠加速推上市,预计10月完成IPO

NAND闪存原厂铠侠Kioxia拟趁着半导体市场回暖及企业财务状况显著提升的契机,加速推进其上市进程。 据报道,公司计划最快于8月底提交IPO申请,目标是在2024年10月末于东京证券交易所完成首次公开募股。此番上市动作不仅反映出市场复苏迹象&…

Postman 怎么测接口?实用教程

在当前,API(应用程序接口)的使用变得越来越普遍。其中,HTTP/HTTPS API 是最常见的一种。无论是开发前端还是后端,测试 API 都是一个关键环节。Postman 是一种流行且强大的 API 测试工具,能够帮助开发人员轻…

P1114 “非常男女”计划最优解

原题地址 P1114 “非常男女”计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码题解 AC代码&#xff08;1&#xff09; 因为用的是级的算法&#xff0c;所以最后一个 了&#xff0c;这里使用特判来得到的&#xff0c;给你们放一下代码&#xff1a; #include <bi…

【2024最新版】图解Mysql数据库配置、命令行及Workbench访问(Windows版本)

目录 1. 准备工作1.1 安装MySQL1.2 验证MySQL的环境变量 2. 环境变量配置3. 访问MySQL3.1 命令行访问MySQL3.2 Workbench访问MySQL 1. 准备工作 1.1 安装MySQL 如果您已经安装了MySQL&#xff0c;请从【2. Mysql 环境配置】开始&#xff1b;如果您没有安装MySQL&#xff0c;请…

06 Shell编程实战——案例1

脚本编程步骤&#xff1a; 脚本编程一般分为4个步骤&#xff0c;即先确定需求&#xff0c;然后再确定你所要用到的语句&#xff0c; 需求分析&#xff1a;根据系统管理的需求&#xff0c;分析脚本要实现的功能、功能实现的层次、实现的命令与语句等&#xff1b;命令测试&…

[Cloud Networking] VLAN

1 为什么需要 VLAN(Virtual Local Area Network) VLAN是一个逻辑网络&#xff0c;VLAN将设备/用户进行逻辑分组&#xff0c;VLAN需要在Switch上创建。为什么需要这样呢&#xff1f;为何不能所有设备都在同一个网络&#xff1f; 如下网络&#xff0c;如果设备过多&#xff0c;…

昇思25天学习打卡营第4天|常见的数据变换 Transforms类型

导入数据集相关库和模块 首先导入了一些必要的库和模块&#xff0c;包括 numpy&#xff08;np 是其常用的别名&#xff09;、PIL 库中的 Image 模块&#xff0c;以及自定义的 download 模块&#xff0c;还有 mindspore.dataset 中的 transforms、vision、text 模块。然后使用 m…

乐队谱在哪里找 乐队功能谱怎么做 Guitar Pro8激活码 吉他谱软件

学习乐队谱对于音乐爱好者来说是一种极具乐趣和挑战的体验。无论是追溯经典曲目还是与其他乐手合作&#xff0c;乐队谱都是实现音乐梦想的必备工具。然而&#xff0c;要找到适合练习的乐队谱并制作出符合乐队演奏需求的功能谱并不容易&#xff0c;需要借助一些方法和工具。下面…

自然语言处理-BERT处理框架-transformer

目录 1.介绍 2.Transformer 2.1 引言 2.2 传统RNN网络的问题 2.3 整体架构 2.4 Attention 2.5 Self-Attention如何计算 3.multi-headed机制 4. BERT训练方法 1.介绍 BERT&#xff1a;当前主流的解决框架&#xff0c;一站式搞定NLP任务。&#xff08;解决一个NLP任务时的考虑…

电脑维护百科全书:从硬件到软件的全面保养指南

前言 在信息时代的滔滔江河中&#xff0c;个人电脑已悄然成为我们学习与工作中不可或缺的智识灯塔。然而&#xff0c;维持其卓越性能与延长使用寿命&#xff0c;绝非偶然&#xff0c;而是建立在细致入微的维护基础之上。本指南犹如一张详尽的航海图&#xff0c;引领你深入探索…

UE5的引擎初始化流程

UE5的引擎初始化流程 首先跟着UE的官方文档[1]获取到UE的源代码&#xff0c;然后在参考GitHub上repo的readme&#xff0c;将UE引擎从源码build出来。以Windows平台为例&#xff0c;先找到引擎的入口函数&#xff1a; int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_op…

wavesummit2024发布飞桨3.0版本

今天网上看了wavesummit2024深度学习开发者大会,本来没有啥期待&#xff0c;结果发现飞桨竟然发布3.0版本了&#xff01; 以下是飞桨框架 3.x 的新特性&#xff1a; 动静统一自动并行&#xff1a; 为了降低大模型的编程难度&#xff0c;飞桨还优化了动静统一的半自动并行编程范…

【Matlab】-- 飞蛾扑火优化算法

文章目录 文章目录 01 飞蛾扑火算法介绍02 飞蛾扑火算法伪代码03 基于Matlab的部分飞蛾扑火MFO算法04 参考文献 01 飞蛾扑火算法介绍 飞蛾扑火算法&#xff08;Moth-Flame Optimization&#xff0c;MFO&#xff09;是一种基于自然界飞蛾行为的群体智能优化算法。该算法由 Sey…

掌握Scrum:敏捷开发中的短期迭代与定期会议

目录 前言1. Scrum概述1.1 什么是Scrum1.2 Scrum的三大支柱 2. 短期迭代&#xff08;Sprint&#xff09;2.1 Sprint规划2.1.1 确定Sprint目标2.1.2 创建Sprint待办列表 2.2 Sprint执行2.2.1 每日站会 2.3 Sprint回顾2.3.1 Sprint评审2.3.2 Sprint回顾 3. 定期会议3.1 产品待办列…

2024年6月27日,欧盟REACH法规新增第31批1项SVHC高关注物质

ECHA公布第31批1项SVHC&#xff0c;物质已增至241项 2024年6月27日&#xff0c;ECHA公布第31批1项SVHC&#xff0c;总数达241项。新增物质未包括磷酸三苯酯&#xff0c;仍在评议中。REACH法规要求SVHC含量超0.1%需告知下游&#xff0c;出口超1吨须通报ECHA。SCIP通报要求SVHC含…

详细介绍LP-SCADA系统的核心数据采集单元

关键字:LP-SCADA系统, 传感器可视化, 设备可视化, 独立SPC系统, 智能仪表系统,SPC可视化,独立SPC系统 SCADA系统的数据采集功能是其核心组成部分&#xff0c;它允许系统从各种传感器、仪器和设备中收集实时数据。以下是SCADA系统数据采集功能的详细描述&#xff1a; 传感器和…

nginx添加模块

问题描述&#xff1a;已经在运行的宝塔中的nginx如何添加模块 1. 进入宝塔nginx的脚本目录 cd /www/server/panel/install 2. 读修改宝塔官方写的脚本 vim nginx.sh 3. 找到字符 ./configure - 添加模块 --add-module/home/root/app/nginx-module/echo-nginx-module-0.62 …

代码随想录算法训练营第三十七天|01背包问题、分割等和子集

01背包问题 题目链接&#xff1a;46. 携带研究材料 文档讲解&#xff1a;代码随想录 状态&#xff1a;忘了 二维dp 问题1&#xff1a;为啥会想到i代表第几个物品&#xff0c;j代表容量变化&#xff1f; 动态规划中&#xff0c;每次决策都依赖于前一个状态的结果&#xff0c;在…

构造函数的小白理解

一、实例 using System; using System.Collections; using System.Collections.Generic; using UnityEngine;//定义一个名为Question的类&#xff0c;用于存储问题及相关信息 [Serializable] public class Question {public string questionText;//存储题目文本字段public str…