python 多任务之多线程

多线程

线程是程序执行的最小单位,实际上进程只负责分配资源,而利用这些资源执行程序的是线程,也就是说进程是线程的容器,一个进程中最少有一个线程来负责执行程序,它可以与同属一个进程的其它线程共享进程所拥有的全部资源

 

为什么要选择线程,而不选择进程

进程:就像同时和两个人聊QQ,就需要打开两个QQ软件,会占用没必要的资源

线程:就像同时和两个人聊QQ,只需要打开两个窗口就可以了,也会节省很多资源

 

线程的创建步骤

1.导入所需要的线程模块
import threading

2.通过线程类创建线程对象
线程对象 = threading.Thread(target=任务名)

3.启动线程
线程对象.start()

 

多线程的使用

import threading
import time

def eat():
    for i in range(5):
        print('正字吃饭=============')
        time.sleep(0.5)        # 等待0.5秒后再执行


def music():
    for i in range(5):
        print('正在唱歌=============')
        time.sleep(0.5)       # 等待0.5秒后再执行


if __name__ == '__main__':

    eat_thread = threading.Thread(target=eat,)
    music_thread = threading.Thread(target=music,)

    eat_thread.start()
    music_thread.start()

执行结果

9c37548225bf485e87a7074091b6ef7d.png

 

线程执行任务函数的传参

  • 元组方式传参:元组方式传参一定要和参数的顺序保持一致
  • 字典方式传参:字典方式传参字典中的key一定要和参数名保持一致
import threading
import time

def eat(num, name):
    for i in range(num):
        print(f'{name}正字吃饭=============')
        time.sleep(0.5)        # 等待0.5秒后再执行


def music(num, name):
    for i in range(num):
        print(f'{name}正在唱歌=============')
        time.sleep(0.5)       # 等待0.5秒后再执行


if __name__ == '__main__':

    eat_thread = threading.Thread(target=eat, args=(3, '张三'))
    music_thread = threading.Thread(target=music, kwargs={'num': 5, 'name': '李四'})

    eat_thread.start()
    music_thread.start()

执行结果

4b68f729761a49a087abf43ea2e986ca.png

 

守护主线程

主线程会等待所有的子线程执行结束后主线程再结束,但是也是可以主线程不等待子线程执行完成,可以设置守护主线程

两种方式

        1、threading.Thread(target=work, daemon=True)
        2、线程对象.setDaemon(True)

不设置守护主线程的情况下

import threading
import time

def eat():
    for i in range(10):
        print('正在吃饭==========')
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建子线程
    eat_thread = threading.Thread(target=eat,)
    # 启动子线程
    eat_thread.start()
    time.sleep(2)
    print('主线程执行完毕========')

执行结果

f72bfe0294c24f8196ba8219d3992400.png

方式一守护主线程

import threading
import time

def eat():
    for i in range(10):
        print('正在吃饭==========')
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建子线程
    eat_thread = threading.Thread(target=eat, daemon=True)
    # 启动子线程
    eat_thread.start()
    time.sleep(2)
    print('主线程执行完毕========')

执行结果

5bd2e2a5ba544ff3960d93a17fc2bc26.png

方式二守护主线程

import threading
import time

def eat():
    for i in range(10):
        print('正在吃饭==========')
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建子线程
    eat_thread = threading.Thread(target=eat,)
    # 需要写在开启子线程前面
    eat_thread.setDaemon(True)
    # 启动子线程
    eat_thread.start()
    time.sleep(2)
    print('主线程执行完毕========')

执行结果

5a8827d6caf14c738de645239e8e8ef0.png

 

线程的执行顺序

一个进程里面,多个线程在执行,线程的执行是无序的,是由CPU调度决定某个线程先执行

获取当前线程的信息

1、通过current_thread方法获取线程对象的信息,例如被创建的顺序
current_thread_info = threading.current_thread()

print(current_thread_info)

import threading
import time

def thread_info():

    time.sleep(0.5)

    current_thread_info = threading.current_thread()
    print(current_thread_info)

if __name__ == '__main__':

    for i in range(5):
        sub_thread = threading.Thread(target=thread_info,)
        sub_thread.start()

执行结果

18399294b3cd4791b928890ec68e2e0b.png

 

线程间共享全局变量

多个线程都是在同一个进程中,多个线程使用的资源都是同一个进程中的资源,因此多线程间是共享全局变量

import time
import threading

def write_date():
    for i in range(3):
        my_list.append(i)
    print('这是子线程写入的表:', my_list)

def read_date():
    print('这是子线程读数据:', my_list)

my_list = []
if __name__ == '__main__':

    write_thread = threading.Thread(target=write_date)
    read_thread = threading.Thread(target=read_date)

    write_thread.start()
    time.sleep(1)
    read_thread.start()
    time.sleep(1)

    print('这是主线程读的数据:', my_list)

执行结果

b397a28e67364eb0ad84a5e5714bd36e.png

 

线程之间共享全局变量数据出现错误问题

解决办法

  • 同步:就是协同步调,按预定的先后次序进行运行。比如现实生活中的对讲机,你说一句我说一句,不能一起说
  • 使用线程同步:也就是互斥锁,同一时刻只能有一个线程去操作全局变量

不使用的情况下

import threading

# 定义全局变量
num = 0

def sum_num1():
    for i in range(1000):
        global num
        num += 1
    print('num1:', num)

def sum_num2():
    for i in range(1000):
        global num
        num += 1
    print('num2:', num)

if __name__ == '__main__':

    sum1 = threading.Thread(target=sum_num1,)
    sum2 = threading.Thread(target=sum_num2,)

    sum1.start()
    sum2.start()

执行结果

551170087d1d49cfb3ec417c2b8cd514.png

把num加大

import threading

# 定义全局变量
num = 0

def sum_num1():
    for i in range(1000000):      # 多加了几个0
        global num
        num += 1
    print('num1:', num)

def sum_num2():
    for i in range(1000000):       # 多加了几个0
        global num
        num += 1
    print('num2:', num)

if __name__ == '__main__':

    sum1 = threading.Thread(target=sum_num1, )
    sum2 = threading.Thread(target=sum_num2, )

    sum1.start()
    sum2.start()

执行结果

9d36e411c39e45bca5b6b981aa49e3de.png

 

互斥锁的使用

对共享数据进行锁定,保证同一时刻只有一个线程去操作

互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到的线程进行等候,等锁使用完释放后,其它等待的线程再去抢这个锁

使用

1、创建互斥锁
mutex  = threading.Lock()
2、上锁
mutex .acquire()
3、释放锁
mutex .release()

import time
import threading

# 定义全局变量
num = 0

def sum_num1():
    # 上锁
    mutex.acquire()
    for i in range(1000000):
        global num
        num += 1
    print('num1:', num)
    # 释放锁
    mutex.release()

def sum_num2():
    # 上锁
    mutex.acquire()
    for i in range(1000000):
        global num
        num += 1
    print('num2:', num)
    # 释放锁
    mutex.release()

if __name__ == '__main__':
    # 创建锁
    mutex = threading.Lock()
    # 创建子线程
    sum1 = threading.Thread(target=sum_num1, )
    sum2 = threading.Thread(target=sum_num2, )
    # 启动子线程
    sum1.start()
    sum2.start()

    time.sleep(5)
    print(num)

执行结果

 09a331ddb60b4268b08ce07325bd20b0.png

死锁

一直等待对方释放锁的情况就是死锁,死锁会造成程序的停止响应,不能再处理其他任务

产生死锁的原因:没有及时或者在正确的位置释放锁

 

 

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

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

相关文章

基于Simulink的双端行波测距

1 输电线路故障仿真模型 基于双端行波测距理论,在MATLAB软件中搭建的三相50Hz的输电线路故障仿真模型如图1所示,该模型包含了三相电源、输电线路、故障发生器和示波器模块等。主要仿真参数设置如下:仿真时间为 0~0.1s,采用固定步长 10-7和ode3 算法&…

为什么Kubernetes(K8S)弃用Docker:深度解析与未来展望

为什么Kubernetes弃用Docker:深度解析与未来展望 🚀 为什么Kubernetes弃用Docker:深度解析与未来展望摘要引言正文内容(详细介绍)什么是 Kubernetes?什么是 Docker?Kubernetes 和 Docker 的关系…

小柴带你学AutoSar系列一、基础知识篇(5)makefile基础

Flechazohttps://www.zhihu.com/people/jiu_sheng 小柴带你学AutoSar总目录https://blog.csdn.net/qianshang52013/article/details/138140235?spm=1001.2014.3001.5501

动态IP在云计算中的应用与优势(短效IP的作用)

一、云计算概述 云计算是指通过互联网将计算资源和服务提供给用户的一种模式。它具有高灵活性、可扩展性和成本效益等特点,使得企业能够快速响应市场变化,降低IT投入成本。云计算的核心优势在于其资源的动态分配和高效利用。 二、动态IP在云计算中的角…

nodejs最新某东h5st(4.7.2)参数分析与javascript逆向纯算法还原(含算法源码)(2024-06-09)

一、作者声明: 文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除! 二 、写在前面 h5st从4.1一路更新到4.7.2,逐渐vmp…

电子电气架构 ---车载安全防火墙

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

gdb 【Linux】

程序发布方式:  1、debug版本:程序会被加入调试信息,以便于进行调试。  2、release版本:不添加任何调试信息,是不可调试   确定一个可执行程序是debug,还是release [cxqiZ7xviiy0goapxtblgih6oZ test_g…

1.2-自然语言的分布式表示-基于计数的方法

本篇笔记对应的视频链接为: 3-基于计数的方法表示单词-将文字转换成编号的预处理工作_哔哩哔哩_bilibili;4-基于计数的方法表示单词-使用共现矩阵进行单词的分布式表示_哔哩哔哩_bilibili;5-基于计数的方法表示单词-单词之间相似度计算_哔哩哔…

都怪我当初没有好好了解你,Java虚拟机(JVM)

初始JVM JVM本质是一个运行在计算机上的程序,作用是运行Java字节码文件。 下面是它的运行流程: 看完上述运行过程,现在提出一个问题:Java是编译型语言还是解释型语言? 这里先补充什么是编译,什么是解释&am…

泛微开发修炼之旅--13通过Ecology拦截器(注解的方式),拦截后端接口,实现接口执行成功后或执行前操作源码示例

文章链接:泛微开发修炼之旅--13通过Ecology拦截器(注解的方式),拦截后端接口,实现接口执行成功后或执行前操作源码示例

Codeforces Round 949 (Div. 2) A~D

A. Turtle and Piggy Are Playing a Game (思维) 题意: 给出一个整数 x x x ,使得 l ≤ x ≤ r l \le x \le r l≤x≤r ,其中 l , r l, r l,r 为给定值。同时保证 2 l ≤ r 2l \le r 2l≤r 。 执行以下操作&…

【C51】C51单片机实现的 抽奖机 设计与编程指南

文章目录 前言:1. 实现效果2. 准备工作3. 编写代码总结: 前言: 在本文中,我们将介绍如何使用C51单片机来实现一个简单的抽奖机。这个项目不仅能够展示C51单片机的基本应用,还能让我们了解如何通过编程来控制硬件&…

Unity协程学习心得

前言 个人总结的一些Unity协程学习心得,如有不对请在评论区指出一起学习!感谢。 在Unity编程中谈到异步逻辑,可以考虑使用协程来实现。协程(Coroutine)在Unity中的主要作用就是把一个任务暂停(挂起&#…

Java集合汇总

Java中的集合框架是Java语言的核心部分,提供了强大的数据结构来存储和操作对象集合。集合框架位于java.util包中,主要可以分为两大类:Collection(单列集合)和Map(双列集合)。下面是对它们的总结…

NXP i.MX8系列平台开发讲解 - 3.14 Linux 之Power Supply子系统(二)

专栏文章目录传送门:返回专栏目录 Hi, 我是你们的老朋友,主要专注于嵌入式软件开发,有兴趣不要忘记点击关注【码思途远】 目录 1. 前言 2. 芯片简介 2. 系统原理设计 2. 设备树相关 本文实操是基于Android11 系统下i.MX8MQ环境下&#x…

博睿数据应邀出席双态IT用户大会,分享《构建云原生时代的一体化智能可观测性》

5月31日-6月2日,第十二届双态IT用户大会于成都成功举行,此次大会由DCMG和双态IT论坛联合主办,聚焦“信创时代的组织级云原生能力建设”和“组织级云原生运维能力建设”两大会议主题,旨在推动双态IT落地与创新,为企业数…

LabVIEW在高校中的应用

LabVIEW 作为一款功能强大的图形化编程工具,在高校中有广泛的应用。它不仅用于教学实验,还广泛应用于科研项目和工程训练。本文将从教学、科研、实验室管理和学生技能培养等多个角度,详细分析LabVIEW在高校中的应用。 教学应用 课程设计 自动…

快来速领限量免费亚马逊云科技助理级架构师(SAA)和云从业者50%半价考试券

前几天在上海5/29的亚马逊云科技Summit峰会里,小李哥在现场分享了AWS 13张认证大满贯的心得(图1),并且现场招募了自己的云师兄必过班(图2)。 本次必过班也为成员发放AWS SAA(助理级架构师)和云从业者(Cloud Practitioner)50%考试券…

华为防火墙配置 SSL VPN

前言 哈喽,我是ICT大龙。本期给大家更新一次使用华为防火墙实现SSL VPN的技术文章。 本次实验只需要用到两个软件,分别是ENSP和VMware,本次实验中的所有文件都可以在文章的末尾获取。话不多说,教程开始。 什么是VPN 百度百科解…

未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。.net 读取excel的时候报错(实测有效)

1. 下载AccessDatabaseEngine.exe 下载链接 添加链接描述 2. office excel是64为的需要安装【AccessDatabaseEngine.exe】、32位的【AccessDatabaseEngine_X64.exe】 3. 我的是64为,跳过32位安装检测 1. 找到下载的安装包 2.输入安装包文件全称并在后面加上/pas…