Python的多线程

多线程

1. 程序,进程,线程

1、程序是指一组指示计算机或其他具有信息处理能力装置执行动作或做出判断的指令,通常用某种程序设计语言编写,运行于某种目标计算机体系结构上。程序的通俗定义就是:一段可执行的代码

2、进程是计算机中的软件程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。一个运行起来的程序就是一个进程

3、线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有操作系统资源,但是该线程可与同属进程的其他线程共享该进程所拥有的全部资源。

进程是程序的实体,而线程又是进程的实体。进程又是线程的容器。

image-20240422223109872

2. 线程的实现

python两种方法实现线程: Thead类 自定义线程类

01 线程类Thread

  • threading 模块中Thread类

    image-20220117015937582
    • 属性:
      • name 线程的名称
      • target 线程要执行的函数名
      • args 函数的实参列表
    • 方法:
      • start( ) 启动线程的方法
      • run( ) 运行线程 的方法
  • 线程执行的流程:

    • (1)线程对象 调用 start() 方法 启动线程 等待CPU调度
    • (2)当CPU调度到此线程时,线程对象自动调用run()方法运行线程

02 线程实现方式

  • 实现思路: 创建Thread类的实例, 调用start() 启动线程
  • 线程执行的核心: 调用函数
  • 准备:一个函数
  • 第一步:创建线程对象
    • 语法 : 线程对象= Thread( target =函数名, args=(函数的实参列表,))
    • target 线程函数名 ----线程要执行的函数
    • args 线程函数的实参列表,是元组类型
  • 第二步: 启动线程
    • 线程对象.start()
  • 示例: 使用线程 模拟 两个线程在CPU调度下,交替运行
import time
from threading import Thread
#功能方法:数数(从1数到5)
def  show_num(tname):
    for i in  range(6):
        print(tname, i)
        time.sleep( 3 )#暂停3秒,控制输出5个数需要稍长的时间才能完成
        

if __name__ == '__main__':
    print("111111111111111111")
    #创建线程,再启动线程
    t1 =Thread(target= show_num, args=("第一个线程",))
    t1.start()
   
	t2 =Thread(target=show_num,args=("第二个线程",))
    t2.start()
    print("222222222222222222")
'''
线程在CPU的调度下, 交替执行  ----多个线程争抢CPU
小结: 
1. 使用 Thread类 创建线程的语法
2. 理解 就绪的线程被CPU的调度后,自动执行 run()
'''
  • 小结 线程执行的流程:
-- 创建线程对象----------- 线程状态:创建状态  
-- 线程对象调用start() ---------- 线程状态:就绪状态, 等CPU来调度     
-- 当CPU调度到它时,线程对象调用run() 会执行线程函数----------线程状态:运行状态

image-20220117021315099

03.多个线程共享全局变量

  • 当多个线程共享 全局变量时,可能导致全局变量的值会出现不正常
import time
from threading import  Thread
from threading import Lock
num=0  #全局变量
def  set_num( tname ):
    global num
    num+=1
    time.sleep(0.3)  #模拟num 加1减1的操作会花费较长的时间
    num-=1
    print(tname,num)

if __name__ == '__main__':
    t1 =Thread(target=set_num,args=('t1',))
    t1.start()
    t2 = Thread(target=set_num,args=('t2',))
    t2.start()
    t3 = Thread(target=set_num,args=('t3',))
    t3.start()

#理想状态:多个线程操作完后,全局变量的数据还是0

#运行结果:每次运行都有不同的结果, 这是因为 线程由CPU调度,可能一个线程没有执行完就暂停切换到另一个线程执行。

#防止共享数据修改产生不正确数据,就需要在线程更改数据前锁定这个数据,修改完解锁后其它线程才能再更改这个数据

#使用锁 锁定资源(一段代码),这时其它线程不能访问,直到释放锁后 其它线程才可访问 
# 使用threading模块中Lock类 创建锁   lock = Lock()   
# 加锁    lock.acquire() 
# 释放锁  lock.release() 
import time
from threading import  Thread
from threading import Lock
num=0  #全局变量
''''
# 使用threading中Lock 创建锁   lock =Lock()   
# 加锁    lock.acquire() 
# 释放锁  lock.release() 
'''
lock =Lock()
def  set_num( tname ):
    global num
    lock.acquire()  #加锁
    num+=1
    time.sleep(0.3) 
    num-=1
    lock.release() #解锁
    print(tname,num)

#当某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其它线程不能更改,直到该线程释放资源,其他线程才能修改。
  • 互斥锁: 每次只有一个线程进行写入操作,保证了多线程情况 共享数据更改的正确性
  • ​ 定义锁: mylock=threading. Lock()
  • ​ 加锁: mylock.acquire()
  • ​ 解锁: mylock.release()
#==========================使用 自定义线程类 创建3个线程==============================  
import time
from threading import  Thread
from threading import Lock
num = 0  # 全局变量
lock =Lock()
class  MyThread(Thread):
    def run(self) -> None:
        self.set_num()
    def  set_num( self ):
       global num
       lock.acquire() #加锁
        num+=1
        time.sleep(0.3)
        num-=1
        lock.release()  # 解锁
        print(self.name,num)

if __name__ == '__main__':
    t1 =MyThread(name='t1')
    t2 =MyThread(name='t2')
    t3 =MyThread(name='t3')
    t1.start()
    t2.start()
    t3.start()

04 守护线程与阻塞线程

  • # 什么都不设置,按顺序执行主线程,当主线程执行完毕,有未执行完毕的子线程,子线程继续执行
    def demo(num):
        # 循环输出1-10,每次暂停0.1s
        for i in range(num):
            print(i + 1)
            time.sleep(0.1)
    if __name__ == '__main__':
        obj = threading.Thread(target=demo, args=(10,))
        obj.start()
        print('下载完毕')
    
  • # 想让主线程在子线程执行完毕后在执行--->阻塞线程(执行子线程完毕之后最后在执行主线程)obj.join()
    
    def demo(num):
        # 循环输出1-10,每次暂停0.1s
        for i in range(num):
            print(i + 1)
            time.sleep(0.1)
    if __name__ == '__main__':
        obj = threading.Thread(target=demo, args=(10,))
        obj.start()
        阻塞主线程
        obj.join()
        print('下载完毕')
    
  • # 想让主线程执行完毕后马上结束子线程--->守护线程(执行完主线程后马上去中断子线程) obj.daemon = True
    def demo(num):
        # 循环输出1-10,每次暂停0.1s
        for i in range(num):
            print(i + 1)
            time.sleep(0.1)
    if __name__ == '__main__':
        obj = threading.Thread(target=demo, args=(10,))
        obj.daemon = True
        obj.start()
        print('下载完毕')
    
    

05 线程状态(了解):

  • 线程生命周期:

  • 1.新建状态:

    • 创建线程对象 新建状态。
  • 2.就绪状态:

    • 调用 start() 方法后,就绪状态(随时等待 CPU 调度)
  • 3.运行状态:

    • 线程得到了 CPU调度,运行状态 (执行 target 参数的目标函数或者 run() 方法)
  • 4.阻塞状态:

    • 对于获得 CPU 调度却没有执行完毕的线程,就会进入阻塞状态
    • sleep( n ) -----------休眠时间到,转到就绪状态
    • 等待锁--------------等待前面线程释放解锁,转到就绪状态
    1. 死亡状态
  • 线程具有就绪,等待和运行三种基本状态和状态间转换关系

image-20210830134810191

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

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

相关文章

http 3.0 有哪些新特性

HTTP/3 是超文本传输协议(HTTP)的最新主要版本,其显著特点是放弃了传统的TCP作为传输层协议,转而采用基于UDP的QUIC(Quick UDP Internet Connections)协议。以下是HTTP/3利用QUIC实现高性能传输的关键特性&…

检索增强生成(RAG)技术

随着大型语言模型(LLMs)在自然语言处理(NLP)领域的显著进步,它们在多个评估基准测试中显示出超越人类水平的语言和知识掌握能力。然而,这些模型在实际应用中也面临着一系列挑战,如制造事实、知识…

关于stm32cubemx时钟设置中css enable的作用

STM32已提供了一个时钟失常恢复机制(CSS),当系统选择HSE作系工作时钟,并打开了CSS功能后,当HSE由于外部原因而停震时,系统将自动切换到内部HSI运行,并产生NMI中断,于是可以在NMI中断中进行安全处理。在cube…

Java中的BIO、NIO与AIO

1.概述 I/O 模型简单的理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能。Java 共支持 3 种网络编程模型 I/O 模式:BIO、NIO、AIO。 2.Java BIO Java BIO(Blocking I/O):是传统的java io 编程&#…

话题——为什么要学习程序,成为程序员呢?

选择成为一名程序员,这对我而言并非是一时冲动,而是深思熟虑后的坚定选择。在当下这个信息化、数字化的时代,程序员这一职业不仅具有极高的技术含量,更承载了推动社会进步、引领科技发展的重任。特别是在深度学习这一前沿领域&…

【六十四】【算法分析与设计】699. 掉落的方块,离散化操作,线段树优化,区间查询sum+区间更新update

699. 掉落的方块 在二维平面上的 x 轴上,放置着一些方块。 给你一个二维整数数组 positions ,其中 positions[i] [left(i), sideLength(i)] 表示:第 i 个方块边长为 sideLength(i) ,其左侧边与 x 轴上坐标点 left(i) 对齐。 每个…

Midjourney如何利用chaos控制生成图片的差异化

hello 小伙伴们,我是你们的老朋友——树下,今天分享Midjourney提示词常用参数——chaos,话不多说,直接开始~ chaos参数什么意思呢? 它可以用来控制我们生成图片之间的差异化程度的一个参数 通常我们在用Midjourney生…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-1.1

前言: 本文是来自哔哩哔哩网站上视频“正点原子[第二期]Linux之ARM(MX6U)裸机篇”的学习笔记,在这里会记录下正点原子Linux ARM MX6ULL 开发板根据配套的哔哩哔哩学习视频所作的实验和笔记内容。本文大量的引用了正点原子哔哔哩网…

服务器 BMC(基板管理控制器,Baseboard Management Controller)认知

写在前面 工作中遇到,简单整理博文内容涉及 BMC 基本认知理解不足小伙伴帮忙指正 不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上春树 基板管理控制器(BMC&…

小米一面:说说MVC与设计模式的关系

前言 大家好,我叫阿杆,不叫阿轩。 先来看看面试环节吧。 面试官:请说说MVC模式是基于哪种设计模式的? 求职者:MVC本身不就是一种设计模式吗? 面试官:我的意思是,MVC是基于23中设计…

SD-WAN为什么在亚太地区普及?

当前,软件定义广域网SD-WAN在亚太地区具有稳固的地位。它看起来是技术与地形的完美结合,因为亚太地区拥有许多大国,其中一些国度辽阔,人口分布在广阔的地理区域和偏远地区,如印度,澳大利亚,越南…

Introducing Meta Llama 3: The most capable openly available LLM to date

要点 今天,我们推出 Meta Llama 3,这是我们最先进的开源大型语言模型的下一代。Llama 3型号将很快在AWS,Databricks,Google Cloud,Hugging Face,Kaggle,IBM WatsonX,Microsoft Azur…

代码随想录算法训练营第四十六天| LeetCode139.单词拆分

一、LeetCode139.单词拆分 题目链接/文章讲解/视频讲解:https://programmercarl.com/0139.%E5%8D%95%E8%AF%8D%E6%8B%86%E5%88%86.html 状态:已解决 1.思路 单词明显就是物品,字符串s明显就是背包,那么问题就变成了物品能不能把背…

Three 银河系

总体效果图 当然,这也只是银河系的一部分,要想知道全景视野下的银河系是什么样的,只有通过科学家依据观测结果所制作的绘图来实现,因为银河系实在是太大了,目前的技术水平还无法实现全景捕捉。绘制的这张三维立体图像…

记录:阿里云服务器网站搭建(4)

Docker安装Nginx 现阶段主要目的是做一些静态资源路径的转发代理,相当于一个web服务器,tomcat也可以设置凡访问静态资源。但考虑到后续还需要作为代理服务器对域名等进行代理转发,所以使用nginx。 准备好要挂载的nginx配置目录 mkdir -p /m…

React-RTK

​🌈个人主页:前端青山 🔥系列专栏:React篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容:React-RTK 目录 1、介绍 2、安装 3、编写RTK使用示例 4、官方提供项目包示例 创建 Redux …

ROS 2边学边练(33)-- 写一个静态广播(C++)

前言 通过这一篇我们将了解并学习到如何广播静态坐标变换到tf2(由tf2来转换这些坐标系)。 发布静态变换对于定义机器人底座与其传感器或非移动部件之间的关系非常有用。例如,在以激光扫描仪中心的坐标系中推理激光扫描测量数据是最简单的。 这…

基于人工智能的机动车号牌检测与推理系统v1.0

基于人工智能的机动车号牌检测与推理系统v1.0代码重构与实现。 目前整合3中现有算法,并完成阶段性改造,包括【传统方法检测车牌,SVM推理字符】、【YOLO方法检测车牌,SVM推理字符】、【YOLO方法检测车牌,CNN推理字符】&…

MapReduce案例-电影网站数据统计分析

本文适合大数据初学者学习MapReduce统计分析业务问题的步骤和基础的MapReduce编程方法,初步掌握Hadoop对计算任务的管理。 本文末尾有全部数据集和完整代码连接。 1.准备工作 安装Hadoop:Hadoop 3.3.2 离线安装-CSDN博客 按照好Hadoop之后要检查一下datanode运行情况…

Llama网络结构介绍

LLaMA现在已经是开源社区里炙手可热的模型了,但是原文中仅仅介绍了其和标准Transformer的差别,并没有一个全局的模型介绍。因此打算写篇文章,争取让读者不参考任何其他资料把LLaMA的模型搞懂。 结构 如图所示为LLaMA的示意图,由…