在Python中使用多线程(通俗版本)

news2024/9/25 9:38:59

一、多线程的介绍:

1.进程

通常一个进程包含一个或者多个线程,每个进程有自己独立的一块内存空间,所有的线程共享这一块空间,例如:在Windows操作系统中,一个运行的xx.exe就是一个进程。

2.线程

一个进程总得有多个执行任务吧,例如我有一个学生信息查询进程,当我想要查询某个学生信息时,它大致包含以下几个任务

1.进程接收学生信息并发送给服务器

2.进程接收学生信息

3.进程分析学生信息

4.进程将学生信息展示出来

不难理解,如果一个进程只有一个线程,那么这个线程将会按照顺序执行四个任务,那么总耗费时间就是t1+t2+t3+t4的时间。

但是如果我们使用多线程,我们拥有三个线程,那么我们就可以边接收学生信息(任务二),边分析学生信息(任务三),边展示学生信息(任务四)

那么总时间将无限接近于t1+t2

可以看到,这大大提升了工作效率,除此之外,线程还拥有更小的系统开销代价,相较于多进程来说,多线程的开销远远小于多进程,并且由于线程间数据可以共享,为此在处理“密集型I/O型任务”时,我们可以使用多线程来提升工作效率。

密集型I/O型任务举例爬虫中大量获取接口、GUI页面的子页面。

二、多线程的使用

0.多线程的使用方式:

在Python中实现多线程的库有很多,在这里我们使用最常见的“threading”库。

1.显示线程信息的属性的方法:

import threading

if __name__ == "__main__":
    print("当前进程数量为:",threading.active_count())
    print("当前所有的线程为:",threading.enumerate())    #以列表的形式显示
    print("当前线程为:",threading.current_thread())

效果图:

2.添加线程

在threading中添加线程,使用内置的“Thread”类,先创建Thread对象,再使用start()方法启动这个线程。
threading.Thread(target=Nonename=Noneargs=()kwargs={}*daemon=None)

其中:

1.target为函数名,或者可调用对象

2.name是线程名称,如果不指定系统会随机生成。

3.args用于发起调用目标函数的参数列表元组默认是()

4.kwargs是用于发起调用目标函数的关键字参数字典,默认是{}

5.daemon(3.3版本新增),daemon如果不是默认值None,则该线程为守护线程。

import threading
import time

def job1():
    #让这个线程暂停5秒,便于区分
    time.sleep(1)
    print("job1成功执行啦,执行该函数的线程是:",threading.current_thread())

if __name__ == "__main__":
    #创建一个线程,并且不给该线程使用name参数指定名字
    my_thread_1 = threading.Thread(target=job1)
    #创建一个线程,并且给该线程使用name参数指定名字
    my_thread_2 = threading.Thread(target=job1,name="t1")
    #启动两个线程
    my_thread_2.start()
    my_thread_1.start()
    print("当前进程数量为:",threading.active_count())
    print("当前所有的线程为:",threading.enumerate())    #以列表的形式显示
    print("当前线程为:",threading.current_thread())

效果图:

可以看到,线程1和线程2是同时完成的,因为两条打印语句都“挤到一起”了。

3.线程间的堵塞

3.1为什么要使用堵塞

我们继续看上面提到的学生查询例子,在任务四中,进程需要展示学生信息,但如果任务四的执行速度大于任务三大于任务二,会出现什么状况呢?

此时,学生的全部信息尚未接收完全,但是任务四的线程已经执行完毕了,这就导致最后展示出来的学生信息是不全的,这显然不是我们想要的结果,那我们该怎么办呢?

这就不得不搬出线程的“堵塞”了。

3.2堵塞的作用

线程堵塞顾名思义,会将某个线程堵住,从而使这个线程卡住,直到解除线程堵塞。

为此我们可以适当的将任务四的线程堵塞,直到任务二任务三的线程执行的差不多了,我们再解除任务四的堵塞即可

3.3使用join()函数来完成线程堵塞的操作

join()函数的使用方法:

A函数中使用join()函数,那么A函数会卡住,直到被使用join()函数的线程执行完毕,函数A才会继续进行

import threading
import time

def B():
    #让这个线程暂停1秒,便于区分
    time.sleep(1)
    print(f"嗨,我是B函数~我被线程{threading.current_thread()}使用.")

def A():
    #创建B线程,注意的是A本身就是一个线程A
    new_threading = threading.Thread(target=B)
    #启动B线程
    new_threading.start()
    #堵塞A线程,使用线程B堵塞A线程。
    new_threading.join()
    print(f"嗨,我是A函数~我被线程{threading.current_thread()}使用.")
    print("当前进程数量为:",threading.active_count())
    print("所有的线程为:",threading.enumerate())    #以列表的形式显示

if __name__ == "__main__":
    A()

效果图:

可以看到,线程B在执行完B函数之后,自动销毁了,此时线程数量仅为1了。

3.4线程执行的结果使用Queue来存储

虽然线程之间共享数据,但是在Threading库中,除主线程外,子线程执行的结果并不能通过return来返回数据,为此我们需要使用“Queue”来存储。

可以理解为,子线程虽然无法返回数据,但是子线程之间可以用Queue队列管道来存储结果

为此,我们需要安装queue库

import threading
from queue import Queue

def job(l, q):
    for i in range(len(l)):
        l[i] = l[i] * 10
    #使用put方法向队列中添加数据
    q.put(l)


def tasks():
    # 创建队列
    q = Queue()
    # 线程列表
    threads = []
    # 二维列表
    data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    for i in range(3):
        t = threading.Thread(target=job, args=(data[i], q))
        t.start()
        threads.append(t)

    # 对所有线程进行阻塞
    for thread in threads:
        thread.join()
    results = []
    # 将新队列中的每个元素挨个放到结果列表中
    for _ in range(3):
        #使用get方法在队列中取数据.
        #当对列为空时,线程会卡在这里,一直在请求获取数据,直到获取到数据为止.
        #可以使用q.empty()方法判断队列是否为空.
        results.append(q.get())
    print(results)


if __name__ == "__main__":
    tasks()

效果图:

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

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

相关文章

lua调用C++函数

第一步搭建lua的环境. win10 lua环境搭建-CSDN博客 我使用的环境是win10vs2015lua54 先来个最简单的lua调用C函数, 无参数无返回值的 第一步:定义C函数. int CTest(lua_State* L) // 返回值是固定的int类型,返回0表示没有返回参数,返回1表示有一个返回参数 {std::cout &l…

什么是支持向量机(Support vector machine)和其原理

作为机器学习的基础算法,SVM被反复提及,西瓜书、wiki都能查到详细介绍,但是总是觉得还差那么点,于是决定自己总结一下。 一、什么是SVM? 1、解决什么问题? SVM,最原始的版本是用于最简单的线…

【C++从0到王者】第五十站:B树

文章目录 一、内查找与外查找1.内查找2.外查找 二、B树概念三、B树的插入1.B树的插入分析2.B树插入总结3.插入代码实现4.B树满树和最空时候的对比5.B树的删除6.遍历B树7.B树的性能分析 一、内查找与外查找 1.内查找 像我们之前所用的在内存中的查找就是内查找 种类数据格式时…

Arduino应用开发——使用GUI-Guider制作LVGL UI并导入ESP32运行

Arduino应用开发——使用GUI-Guider制作LVGL UI并导入ESP32运行 目录 Arduino应用开发——使用GUI-Guider制作LVGL UI并导入ESP32运行前言1 使用GUI-Guider设计UI1.1 创建工程1.2 设计UI 2 ESP工程导入UI2.1 移植LVGL2.2 移植UI文件2.3 调用UI文件2.4 烧录测试 结束语 前言 GU…

STM32(5) GPIO(2)输出

1.点亮LED 1.1 推挽接法和开漏接法 要想点亮LED,有两种接法 推挽接法: 向寄存器写1,引脚输出高电平,LED点亮;向寄存器写0,引脚输出低电平,LED熄灭。 开漏接法: 向寄存器写0&…

杂记-买华强北电子产品的教训

之前不信邪,去华强北买了一个西部数据所谓全新的机械硬盘,1T,差不多300元。用了不到一年就坏了。然后去官网查S/N,结果查无device。Onedrive同步的时候,我把同步路径设置为机械硬盘,结果机械硬盘崩的时候&a…

HarmonyOS Next 实现登录注册页面(ARKTS) 并使用Springboot作为后端提供接口

1. HarmonyOS next ArkTS ArkTS围绕应用开发在 TypeScript (简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集 ArkTS在TS的基础上扩展了struct和很多的装饰器以达到描述UI和状态管理的目的 以下代码是一个基于…

【和鲸冬令营】通过数据打造爆款社交APP用户行为分析报告

【🐋和鲸冬令营】通过数据打造爆款社交APP用户行为分析报告 文章目录 【🐋和鲸冬令营】通过数据打造爆款社交APP用户行为分析报告1 业务背景2 数据说明3 数据探索性分析4 用户行为分析4.1 用户属性与行为关系分析4.2 转化行为在不同用户属性群体中的分布…

Android之MQTT的使用

MQTT的简单介绍 MQTT是广泛应用于物联网的传输协议,基于TCP MQTT有一个代理服务器,其客户端可以订阅主题或向一个主题发送消息,从而实现通信 MQTT 设计了 3 个 QoS 等级。 QoS 0:消息最多传递一次,如果当时客户端不…

Jmeter基础使用---Token鉴权接口关联

接口测试流程: 查看API接口文档,熟悉接口业务(地址、端口、参数、鉴权、状态码)设计接口测试用例(正例:正确的结果;反例:鉴权异常、参数异常、兼容异常、其他异常)使用接…

Java中的List

List集合的特有方法 方法介绍 方法名描述void add(int index,E element)在此集合中的指定位置插入指定的元素E remove(int index)删除指定索引处的元素,返回被删除的元素E set(int index,E element)修改指定索引处的元素,返回被修改的元素E get(int inde…

rtt的io设备框架面向对象学习-io设备管理层

目录 1.设备基类2.rtt基类2.1 rtt基类定义2.2 对象容器定义2.3 rtt基类构造函数 3.io设备管理接口4.总结 这层我的理解就是rtt基类和设备基类所在,所以抽离出来好点,不然每个设备类都要重复它。 1.设备基类 /include/rtdef.h中定义了设备基类struct rt_…

Spring:EnclosingClass工具类分辨

Spring:EnclosingClass工具类分辨 1 前言 通过Spring的工具分辨EnclosingClass类。 测试类如下: package com.xiaoxu.test.enclosingClass;/*** author xiaoxu* date 2024-01-18* java_demo2:com.xiaoxu.test.enclosingClass.Outter*/ public class …

计算机专业必看的几部电影推荐

计算机专业必看的几部电影,就像一场精彩的编程盛宴!《黑客帝国》让你穿越虚拟世界,感受高科技的魅力;《社交网络》揭示了互联网巨头的创业之路,《源代码》带你穿越时间解救世界,这些电影不仅带我们穿越到科…

模型部署 - onnx 的导出和分析 -(1) - PyTorch 导出 ONNX - 学习记录

onnx 的导出和分析 一、PyTorch 导出 ONNX 的方法1.1、一个简单的例子 -- 将线性模型转成 onnx1.2、导出多个输出头的模型1.3、导出含有动态维度的模型 二、pytorch 导出 onnx 不成功的时候如何解决2.1、修改 opset 的版本2.2、替换 pytorch 中的算子组合2.3、在 pytorch 登记&…

SpringBoot+Maven多环境配置模式

我这里有两个配置文件 然后在最外层的父级POM文件里面把这个两个配置文件写上 <profiles><profile><id>druid</id><properties><spring.profiles.active>druid</spring.profiles.active></properties><activation><…

管理系统提升:列表页构成要素,拒绝千篇一律

大家伙&#xff0c;我是大千UI工场&#xff0c;专注UI知识案例分享和接单&#xff0c;本期带来B端系统列表页的分享&#xff0c;欢迎大家关注、互动交流。 一、什么是列表页 管理系统列表页是指管理系统中用于展示和管理数据的页面&#xff0c;通常以表格或列表的形式呈现。列…

经典语义分割(一)利用pytorch复现全卷积神经网络FCN

经典语义分割(一)利用pytorch复现全卷积神经网络FCN 这里选择B站up主[霹雳吧啦Wz]根据pytorch官方torchvision模块中实现的FCN源码。 Github连接&#xff1a;FCN源码 1 FCN模型搭建 1.1 FCN网络图 pytorch官方实现的FCN网络图&#xff0c;如下所示。 1.2 backbone FCN原…

斐波那契数列模型---使用最小花费爬楼梯

746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&#xff09; 1、状态表示&#xff1a; 题目意思即&#xff1a;cost[i]代表从第i层向上爬1阶或者2阶&#xff0c;需要花费多少力气。如cost[0]&#xff0c;代表从第0阶爬到第1阶或者第2阶需要cost[0]的力气。 一共有cost.…

Java - List集合与Array数组的相互转换

一、List 转 Array 使用集合转数组的方法&#xff0c;必须使用集合的 toArray(T[] array)&#xff0c;传入的是类型完全一样的数组&#xff0c;大小就是 list.size() public static void main(String[] args) throws Exception {List<String> list new ArrayList<S…