【python学习】多线程编程的背景、定义、特点、优缺点、使用场景和示例以及和单线程的区别

引言

随着计算机技术的发展,多核处理器已经成为了主流,为了充分利用多核处理器带来的并行计算能力,提高程序的执行效率和响应速度,多线程编程变得尤为重要
Python作为一种高级编程语言,提供了多线程编程的支持,允许开发者创建能够在后台执行任务的线程,从而实现程序的并发执行

文章目录

  • 引言
  • 一、定义
  • 二、特点
    • 2.1 并发性
    • 2.2 资源共享
    • 2.3 轻量级
  • 三、优点
    • 3.1 提高程序响应性
    • 3.2 改善资源利用率
    • 3.3 简化程序结构
  • 四、缺点
    • 4.1 全局解释器锁(GIL)
    • 4.2 线程安全问题
    • 4.3 调试困难
  • 五、使用场景
    • 5.1 I/O密集型任务
    • 5.2 图形用户界面(GUI)应用
    • 5.3 并行任务分解
  • 六、示例
  • 七、多线程编程与单线程的区别
    • 7.1 执行模型
      • 7.1.1 单线程编程
      • 7.1.2 多线程编程
    • 7.2并行与并发
      • 7.2.1 单线程编程
      • 7.2.2 多线程编程
    • 7.3 性能
      • 7.3.1 单线程编程
      • 7.3.2 多线程编程
    • 7.4 复杂性
      • 7.4.1 单线程编程
      • 7.4.2 多线程编程
    • 7.5 同步和线程安全
      • 7.5.1 单线程编程
      • 7.5.2 多线程编程
    • 7.6 示例对比
      • 7.6.1 单线程示例
      • 7.6.2 多线程示例
  • 八、总结(思维导图)

一、定义

Python多线程编程是指在Python程序中创建并管理多个线程的过程
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位
Python中,通常使用threading模块来创建和管理线程。

二、特点

2.1 并发性

线程可以在同一程序内并发执行,使得程序能够同时处理多个任务

2.2 资源共享

线程共享进程的内存和资源,因此它们之间通信和数据共享相对容易

2.3 轻量级

线程比进程更加轻量级,创建和销毁线程的开销小于进程

三、优点

3.1 提高程序响应性

在执行I/O密集型任务时,多线程可以让程序在等待I/O操作完成的同时继续执行其他任务。

3.2 改善资源利用率

由于线程共享内存和资源,可以减少资源消耗。

3.3 简化程序结构

通过将复杂的任务分解为多个线程,可以使程序结构更加清晰。

四、缺点

4.1 全局解释器锁(GIL)

Python中,由于GIL的存在,即使在多核处理器上,同一时间也只能有一个线程执行Python字节码,限制了线程的并行执行能力

4.2 线程安全问题

线程共享内存可能导致数据竞争和同步问题,需要额外的机制来保证线程安全

4.3 调试困难

线程间的交互可能导致难以追踪和重现的问题

五、使用场景

5.1 I/O密集型任务

如网络请求、文件读写等,线程在等待I/O操作时可以释放GIL,让其他线程运行

5.2 图形用户界面(GUI)应用

在GUI应用中,主线程通常用于处理用户界面事件,而多线程可以用于后台任务,以保持界面的响应性

5.3 并行任务分解

可以将一个大任务分解为多个小任务,由不同的线程并行执行

六、示例

以下是一个简单的Python多线程编程示例,演示了如何在程序中创建两个线程,分别执行不同的任务

import threading
import time
# 定义一个函数供线程执行
def print_numbers():
    for i in range(1, 10):
        print(i)
        time.sleep(0.5)  # 模拟I/O操作
# 定义另一个函数供线程执行
def print_letters():
    for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
        print(letter)
        time.sleep(0.5)  # 模拟I/O操作
# 创建两个线程
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)
# 启动线程
thread1.start()
thread2.start()
# 等待线程结束
thread1.join()
thread2.join()
print("线程执行完毕。")

在这个示例中,我们定义了两个函数print_numbersprint_letters,分别用于打印数字和字母。每个函数都包含一个time.sleep调用,模拟I/O操作。我们创建了两个线程thread1thread2,分别执行这两个函数。通过调用start()方法启动线程,并通过join()方法等待线程执行结束。这个例子展示了如何在Python中使用多线程来并发执行任务。

七、多线程编程与单线程的区别

7.1 执行模型

7.1.1 单线程编程

在单线程编程中,程序按照代码的顺序依次执行,一次只能执行一个任务。如果当前任务需要等待(如I/O操作),整个程序都会等待,直到该任务完成。

7.1.2 多线程编程

多线程编程允许程序同时执行多个线程,每个线程可以看作是一个独立的执行流。这使得程序能够在等待一个线程执行I/O操作时,在另一个线程中继续执行其他任务。

7.2并行与并发

7.2.1 单线程编程

单线程程序通常是顺序执行的,即使在多核处理器上,也不能真正实现并行计算。

7.2.2 多线程编程

多线程程序可以在多核处理器上实现真正的并行计算,尽管在CPython中由于全局解释器锁(GIL)的存在,纯Python代码的并行执行受到限制。

7.3 性能

7.3.1 单线程编程

对于CPU密集型任务,单线程程序通常能够充分利用单个CPU核心的性能。对于I/O密集型任务,单线程程序可能会因为等待I/O操作而造成性能瓶颈。

7.3.2 多线程编程

对于I/O密集型任务,多线程可以提高程序的响应性和性能,因为它可以在一个线程等待I/O操作时,让其他线程继续执行。然而,对于CPU密集型任务,多线程在CPython中可能不会带来性能上的提升,甚至可能因为线程切换和GIL的存在而导致性能下降。

7.4 复杂性

7.4.1 单线程编程

单线程程序的逻辑通常更简单,因为它们顺序执行,没有线程之间的交互和同步问题。

7.4.2 多线程编程

多线程程序更加复杂,因为需要处理线程之间的资源共享、同步(如使用锁、信号量等)以及可能的死锁和竞态条件。

7.5 同步和线程安全

7.5.1 单线程编程

在单线程环境中,不需要担心线程安全问题,因为只有一个线程在操作数据。

7.5.2 多线程编程

在多线程环境中,必须确保线程安全,防止多个线程同时修改同一数据,导致数据不一致或程序崩溃。

7.6 示例对比

以下是一个单线程与多线程的简单对比示例:

7.6.1 单线程示例

import time
def task(name, delay):
    for i in range(5):
        print(f"Task {name}: Iteration {i}")
        time.sleep(delay)
start_time = time.time()
task("A", 1)
task("B", 2)
end_time = time.time()
print(f"Total time: {end_time - start_time} seconds")

在这个单线程示例中,任务A和任务B将依次执行,总执行时间将是两个任务执行时间的总和。

7.6.2 多线程示例

import threading
import time
def task(name, delay):
    for i in range(5):
        print(f"Task {name}: Iteration {i}")
        time.sleep(delay)
start_time = time.time()
thread1 = threading.Thread(target=task, args=("A", 1))
thread2 = threading.Thread(target=task, args=("B", 2))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
end_time = time.time()
print(f"Total time: {end_time - start_time} seconds")

在这个多线程示例中,任务A和任务B将并发执行,总执行时间将接近于执行时间较长的那个任务,因为它们是并行执行的。

总结来说,多线程编程可以提升程序的并发性和响应性,但也带来了额外的复杂性和线程安全问题
单线程编程则更加简单,但无法充分利用多核处理器的能力。选择多线程还是单线程编程取决于具体的应用场景和需求。

八、总结(思维导图)

在这里插入图片描述

PS:知识内容部分取自:https://www.runoob.com/python/python-multithreading.html

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

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

相关文章

电子期刊制作实战教程:从零开始制作

​随着互联网的普及,电子期刊已经成为了信息传递的重要载体。它以便捷、环保、互动性强等特点受到了越来越多人的青睐。那么,如何从零开始制作一份吸引人的电子期刊呢? 1.要制作电子杂志,首先需要选择一款适合自己的软件。比如FLBOOK在线制作…

链表(一)----单链表,链表的删除,链表的合并,链表的划分,头节点

官网地址:https://www.dhcode.cn/p/t_pc/goods_pc_detail/goods_detail/term_624bd804b3d39_Ac0g7V?fromH5true&type3&channel_id&pro_idterm_624bd804b3d39_Ac0g7V 本内容大部分从中截图 讲了三个力扣题:203,21,8…

【postgresql】锁

PostgreSQL 提供了多种锁模式来控制对表和行的并发访问,以确保数据的一致性和完整性。这些锁模式包括表级锁和行级锁,它们可以由应用程序显式控制,也可以在执行大多数 PostgreSQL 命令时自动获取。 锁类型 PostgreSQL类型的锁包括&#xff…

2024-07-14 Unity插件 Odin Inspector1 —— 插件介绍

文章目录 1 介绍2 模块3 学习目的 1 介绍 ​ Odin Inspector 是 Unity 的一个插件,拥有强大、自定义和用户友好的编辑器,而无需编写任何自定义编辑器代码,使得编程过程中的数据可视化更容易实现。 ​ 具体功能包括: 更舒适美观…

网络(二)——套接字编程

文章目录 理解源IP地址和目的IP地址认识端口号认识TCP/UDP协议网络字节序socket编程接口socket 常见APIsockaddr结构 理解源IP地址和目的IP地址 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址; 源IP即发送方的地址,目的IP即接受方的…

创建yaml文件并读取

yaml文件可以存放token数据,那怎么操作存放并读取呢? 1、创建yaml文件 1、导入类库 import yaml 注意要导入的类库,在解释器中叫pyaml 2、创建文件 #创建yaml文件 yamlfileopen("testdata.yaml",w,encodingutf-8) 3、设置数据…

PostgreSQL 中如何解决因频繁的小事务导致的性能下降?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!📚领书:PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中解决因频繁小事务导致性能下降的方法 PostgreSQL 中解决因频繁小事务导致性能下降的方法…

电气工程VR虚拟仿真实训平台以趣味化方式增强吸引力

在工业4.0时代和教育信息化的双重推动下,我们致力于推动实训课件的跨界合作与共创。VR实训课件不仅促进了不同领域、不同行业之间的紧密合作,更让学习变得生动直观。我们凭借3D技术生动、直观、形象的特点,开发了大量配套3D教材,让…

如何允许从互联网(外网)进入路由器管理页面

1.绑定UDP端口 操作如图所示: 2.然后再绑定虚拟换回网卡 3.然后再把出端口编号设置成为2 使他成为一个双向输入输出具体操作如图所示: 4.进入防火墙然后再启动防火墙进行端口配置: 1.进入端口g0/0/0配置ip地址(注意配置的ip地…

游戏热更新——AssetBundle

AssetBundle AssetBundle的定义与使用 AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至是整个场景,可以在游戏运行的时候被加载 AssetBundle自身保存着相互的依赖关系 压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网…

第五天安全笔记(持续更新)

第五天防御笔记 NAT种类: 静态NAT动态NATNapt 特点: 一对多----easy ip 多对多的napt 服务器的映射关系: 1.源NAT----基于IP地址进行转换,包括静态NAT,动态NAT,以及NAPT 2.目标NAT---基于目标IP地址进行转换&a…

网络故障处理及分析工具:Wireshark和Tcpdump集成

Wireshark 是一款免费的开源数据包嗅探器和网络协议分析器,已成为网络故障排除、分析和安全(双向)中不可或缺的工具。 本文深入探讨了充分利用 Wireshark 的功能、用途和实用技巧。 无论您是开发人员、安全专家,还是只是对网络操…

【Linux杂货铺】3.程序地址空间

1.程序地址空间的引入 fork(&#xff09;函数在调用的时候子如果是子进程则返回0&#xff0c;如果是父进程则返回子进程的pid&#xff0c;在代码中我们分别在子进程和父进程读取全局变量g_val的时候居然出现了俩个不同的值。如下&#xff1a; #include<stdio.h> #includ…

t-SNE降维可视化并生成excel文件使用其他画图软件美化

t-sne t-SNE&#xff08;t-分布随机邻域嵌入&#xff0c;t-distributed Stochastic Neighbor Embedding&#xff09;是由 Laurens van der Maaten 和 Geoffrey Hinton 于 2008 年提出的一种非线性降维技术。它特别适合用于高维数据的可视化。t-SNE 的主要目标是将高维数据映射…

FastGPT+OneAI接入网络模型

文章目录 FastGPT连接OneAI接入网络模型1.准备工作2.开始部署2.1下载 docker-compose.yml2.2修改docker-compose.yml里的参数 3.打开FastGPT添加模型3.1打开OneAPI3.2接入网络模型3.3重启服务 FastGPT连接OneAI接入网络模型 1.准备工作 本文档参考FastGPT的官方文档 主机ip接…

QTabWidget、QListWidget、QStackedWidget

The QTabWidget class provides a stack of tabbed widgets. More... The QListWidget class provides an item-based list widget. More... QStringList strlist;strlist<<"系统"<<"外观"<<"截图"<<"贴图"…

宝塔5.9 老版本 登录不进去 密码忘记 验证码不显示笔记

reboot似乎是能重置验证码不显示的唯一方式了 改密码的话在 python tools.py panel 123 我把一段注释了 记录一下 以防以后bug

Matlab-Simulink模型保存为图片的方法

有好多种办法将模型保存为图片&#xff0c;这里直接说经常用的 而且贴到Word文档中清晰、操作简单。 simulink自带有截图功能&#xff0c;这两种方法都可以保存模型图片。选择后直接就复制到截切板上了。直接去文档中粘贴就完事了。 这两个格式效果不太一样&#xff0c;第一种清…

Kafka基础入门篇(深度好文)

Kafka简介 Kafka 是一个高吞吐量的分布式的基于发布/订阅模式的消息队列&#xff08;Message Queue&#xff09;&#xff0c;主要应用与大数据实时处理领域。 1. 以时间复杂度为O(1)的方式提供消息持久化能力。 2. 高吞吐率。&#xff08;Kafka 的吞吐量是MySQL 吞吐量的30…

Java的高级特性

类的继承 继承是从已有的类中派生出新的类&#xff0c;新的类能拥有已有类的属性和行为&#xff0c;并且可以拓展新的属性和行为 public class 子类 extends 父类{子类类体 } 优点 代码的复用 提高编码效率 易于维护 使类与类产生关联&#xff0c;是多态的前提 缺点 类缺乏独…