Python编程进阶:轻松掌握多线程和多进程

大家好,今天我们将讨论如何利用Python执行多线程和多进程任务。它们提供了在单个进程或多个进程之间执行并发操作的方法,并行和并发执行可以提高系统的速度和效率。在讨论多线程和多进程的基础知识之后,我们还将讨论使用Python库实现它们的实际方法。

首先简要讨论并行系统的好处:

  • 改进的性能:有了并发执行任务的能力,可以减少执行时间并提高系统的整体性能。

  • 可扩展性:可以将一个大任务分解为多个较小的子任务,并为它们分配独立的核心或线程,让它们独立执行。这在大规模系统中非常有用。

  • 高效的I/O操作:通过并发的帮助,CPU不必等待进程完成其I/O操作。CPU可以立即开始执行下一个进程,直到前一个进程忙于其I/O操作。

  • 资源优化:通过分割资源,可以防止单个进程占用所有资源。这可以避免较小进程的Starvation(饥饿)问题。

 1.多线程

多线程是在单个进程中实现并行性的一种方法,能够执行同时进行的任务。在单个进程内可以创建多个线程,并在该进程内并行执行较小的任务。单个进程中的线程共享一个公共内存空间,但它们的堆栈跟踪和寄存器是独立的。由于共享内存,它们的计算成本较低。

图片

单线程和多线程Env.

Python中的多线程主要用于执行I/O操作,即如果程序的某个部分正在执行I/O操作,则其余程序可以保持响应。然而在Python的实现中,由于全局解释器锁(GIL)的存在,多线程无法实现真正的并行性。

简而言之,GIL是一个互斥锁,一次只允许一个线程与Python字节码交互,即使在多线程模式下,一次也只能有一个线程执行字节码。

这样做是为了在CPython中保持线程安全,但它限制了多线程的性能优势。为了解决这个问题,Python有一个单独的多进程库,将在之后进行讨论。

不断在后台运行的线程称为守护线程,它们的主要工作是支持主线程或非守护线程。守护线程不会阻塞主线程的执行,甚至会在主线程执行完毕后继续运行。

在Python中,守护线程主要用作垃圾回收器。它会默认销毁所有无用的对象并释放内存,以便主线程可以正常使用和执行。

2.多进程

多进程用于执行多个进程的并行执行,它可以帮助实现真正的并行性,因为可以同时执行不同的进程,并且每个进程都拥有自己的内存空间。它使用CPU的独立核心,并且在执行进程间的数据交换时也很有帮助。

与多线程相比,多进程的计算成本更高,因为不使用共享内存空间。不过它允许进行独立执行,并克服了全局解释器锁的限制。

图片

多进程环境

上图展示了一个多进程环境,在该环境中,一个主进程创建了两个独立的进程,并为它们分配了不同的工作。

3.多线程实现

现在,我们使用Python实现一个基本的多线程示例。Python有一个内置的threading模块用于多线程实现。

3.1导入库:

import threading
import os

3.2计算平方的函数:

这是一个用于计算数字平方的简单函数,它接受一个数字列表作为输入,并输出列表中每个数字的平方,同时输出使用的线程名称和与该线程关联的进程ID。

def calculate_squares(numbers):for num in numbers:square = num * numprint(f"Square of the number {num} is {square} | Thread Name {threading.current_thread().name} | PID of the process {os.getpid()}")

3.3主函数:

本示例有一个数字列表,将其平均分成两半,并分别命名为first_halfsecond_half,现在将为这些列表分配两个独立的线程t1t2

Thread函数创建一个新线程,该线程接受一个带有参数列表的函数作为输入,还可以为线程分配一个单独的名称。

.start()函数将开始执行这些线程,而.join()函数将阻塞主线程的执行,直到给定的线程完全执行完毕。

if __name__ == "__main__":numbers = [1, 2, 3, 4, 5, 6, 7, 8]half = len(numbers) // 2first_half = numbers[:half]second_half = numbers[half:]t1 = threading.Thread(target=calculate_squares, name="t1", args=(first_half,))t2 = threading.Thread(target=calculate_squares, name="t2", args=(second_half,))t1.start()t2.start()t1.join()t2.join()

输出:

Square of the number 1 is 1 | Thread Name t1 | PID of the process 345
Square of the number 2 is 4 | Thread Name t1 | PID of the process 345
Square of the number 5 is 25 | Thread Name t2 | PID of the process 345
Square of the number 3 is 9 | Thread Name t1 | PID of the process 345
Square of the number 6 is 36 | Thread Name t2 | PID of the process 345
Square of the number 4 is 16 | Thread Name t1 | PID of the process 345
Square of the number 7 is 49 | Thread Name t2 | PID of the process 345
Square of the number 8 is 64 | Thread Name t2 | PID of the process 345

注意:上述创建的所有线程都是非守护线程。要创建守护线程,需要编写t1.setDaemon(True),将线程t1设置为守护线程。

现在来了解一下上述代码生成的输出结果,可以观察到两个线程的进程ID(即PID)保持不变,这意味着这两个线程属于同一个进程。

还可以观察到输出并非按顺序生成。第一行中可以看到是线程1生成的输出,然后在第三行是线程2生成的输出,接着在第四行,再次是线程1生成的输出,这清楚地表明这些线程是同时工作的。

并发并不意味着这两个线程并行执行,因为一次只有一个线程被执行。它不会减少执行时间,与顺序执行所需的时间相同。CPU开始执行一个线程,但在中途离开,并切换到另一个线程,过一段时间后,又回到主线程,并从上次离开的地方开始执行。

4.多进程实现

目前对多线程及其实现方式和限制已经有基本的了解。现在,是时候学习多进程的实现以及如何克服这些限制了。

在这里将沿用相同的示例,但不再创建两个独立的线程,而是创建两个独立的进程,并讨论观察结果。

4.1导入库:

from multiprocessing import Process
import os

本例将使用multiprocessing模块来创建独立的进程。

4.2计算平方的函数:

该函数将保持不变。只是在这里删除了有关线程信息的打印语句。

def calculate_squares(numbers):for num in numbers:square = num * numprint(f"Square of the number {num} is {square} | PID of the process {os.getpid()}")

4.3主函数:

主函数有一些修改,只是创建了一个独立的进程,而不是线程。

if __name__ == "__main__":numbers = [1, 2, 3, 4, 5, 6, 7, 8]half = len(numbers) // 2first_half = numbers[:half]second_half = numbers[half:]p1 = Process(target=calculate_squares, args=(first_half,))p2 = Process(target=calculate_squares, args=(second_half,))p1.start()p2.start()p1.join()p2.join()

输出:

Square of the number 1 is 1 | PID of the process 1125
Square of the number 2 is 4 | PID of the process 1125
Square of the number 3 is 9 | PID of the process 1125
Square of the number 4 is 16 | PID of the process 1125
Square of the number 5 is 25 | PID of the process 1126
Square of the number 6 is 36 | PID of the process 1126
Square of the number 7 is 49 | PID of the process 1126
Square of the number 8 is 64 | PID of the process 1126

可以观察到,每个列表都由一个独立的进程执行,它们具有不同的进程ID。为了检查进程是否已并行执行,需要创建一个单独的环境,下面我们将讨论这一点。

为了检查是否获得了真正的并行性,在这里将计算使用和不使用多进程的算法运行时间。

为此需要一个包含超过10^6个整数的大型整数列表,可以使用random库生成一个列表,此处将使用Python的time模块来计算运行时间。下面是实现的代码,代码本身很容易理解,也可以随时查看代码注释。

from multiprocessing import Process
import os
import time
import randomdef calculate_squares(numbers):for num in numbers:square = num * numif __name__ == "__main__":numbers = [random.randrange(1, 50, 1) for i in range(10000000)]  # 创建一个包含10^7个整数的随机列表。half = len(numbers) // 2first_half = numbers[:half]second_half = numbers[half:]# ----------------- 创建单进程环境 ------------------------#start_time = time.time()  # 开始计时(不使用多进程)p1 = Process(target=calculate_squares, args=(numbers,))  # 单进程P1执行整个列表p1.start()p1.join()end_time = time.time()  # 结束计时(不使用多进程)print(f"Execution Time Without Multiprocessing: {(end_time-start_time)*10**3}ms")# ----------------- 创建多进程环境 ------------------------#start_time = time.time()  # 开始计时(使用多进程)p2 = Process(target=calculate_squares, args=(first_half,))p3 = Process(target=calculate_squares, args=(second_half,))p2.start()p3.start()p2.join()p3.join()end_time = time.time()  # 结束计时(使用多进程)print(f"Execution Time With Multiprocessing: {(end_time-start_time)*10**3}ms")

输出:

Execution Time Without Multiprocessing: 619.8039054870605ms
Execution Time With Multiprocessing: 321.70287895202637ms

可以观察到,使用多进程的时间几乎是不使用多进程时间的一半。这表明这两个进程在同一时间内并行执行,并展示了真正的并行性行为。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS4.0从零开始的开发教程12给您的应用添加弹窗

HarmonyOS(十)给您的应用添加弹窗 概述 在我们日常使用应用的时候,可能会进行一些敏感的操作,比如删除联系人,这时候我们给应用添加弹窗来提示用户是否需要执行该操作,如下图所示: 弹窗是一种…

智慧路灯杆如何实现雪天道路安全监测

随着北方区域连续发生暴雪、寒潮、大风等气象变化,北方多地产生暴雪和低温雨雪冰冻灾害风险,冬季雨雪天气深度影响人们出行生活,也持续增加道路交通风险。 智慧路灯杆是现代城市不可或缺的智能基础设施,凭借搭载智慧照明、环境监测…

跨境电商如何利用跨境客服软件提升销售额

随着全球化的推进,跨境电商成为了许多企业拓展市场的重要途径。然而,跨境电商面临着语言、文化、时差等多种挑战,为了提供更好的客户服务并提升销售额,跨境电商需要利用跨境客服软件。本文将探讨跨境电商如何利用跨境客服软件来提…

STM32的看门狗(WDG)

WDG(Watchdog)看门狗 看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠…

5G工业物联网网关,比4G工业网关强在哪里?

​随着5G技术的广泛应用,越来越多的行业开始探索如何利用5G网络提升效率和创新能力。其中,工业物联网领域是受益最大的领域之一。作为连接物联网设备和网络的关键组件,5G工业物联网网关在这个变革中发挥着至关重要的作用。本文将深入探讨5G工…

postman脚本生成可执行文件(6)

一.通过Python脚本(executescript.py)执行newman指令 #!usr/bin/python import subprocess from datetime import datetimeclass Newman_automate():Newman_automate():该类主要是定义postman脚本执行__path:cmd命令行中执行newnan脚本指令(…

桌面便签软件哪个好用?可以放在桌面上的便签软件使用哪个

在现代快节奏的生活中,我们时常感到生活与工作的节奏难以协调。繁琐的工作日程与待办任务繁杂交织,往往让我们束手无策,无法高效地进行协调与分配。 桌面便签工具成为了我们处理这些挑战的得力助手。它不仅能够随时提醒我们完成任务&#xf…

three.js(一)

文章目录 three.js环境搭建正文补充 示例效果知识点补充1:一个标准的html知识点补充2:原生的前端框架和Vue框架的区别原生的前端框架Vue框架声明式编程和响应式编程 three.js环境搭建 正文 搭建 Three.js 的环境通常包括以下几个步骤: 1.创建项目目录&#xff1a…

从零开始:VuePress2 + GitHub Pages 搭建你的第一个免费博客网站

可能你也想拥有一个属于自己的博客网站,但是自己搭个博客网站不知道从何下手,而且还需要租个云服务器,虽然一个月只需几十块钱,但是我们的博客网站是要长期维护的,日积月累也要不少钱呢。 现在我就教你用 VuePress2 …

Linux的基本指令和权限的知识

学前的建议:大家不要太关注指令是啥,记不住怎么办(没事,想用时去查就好了),这篇文章重点部分是围绕指令的周边知识。毕竟指令是“死肌肉”,而一些关于Linux和操作系统的理论知识才是最重要滴&am…

Android Studio中配置Flutter插件,创建小项目“hello world”

文章目录 一、下载Flutter SDK二、Android studio中安装Flutter插件三、创建Flutter小项目 一、下载Flutter SDK 打开官网https://flutter.io/setup-windows/下载Flutter sdk并解压到一目录 二、Android studio中安装Flutter插件 Android studio中安装Flutter插件&#x…

文件系统理解

先前的博客我写了关于缓冲区的理解,顺便提及了在内存的文件是怎样管理的,本文就来描述在磁盘上的文件是怎么样。但要先了解了解磁盘。 在笔记本上机械磁盘被固态硬盘代替,因为固态硬盘更快,而且方便携带,机械硬盘若是受…

银河麒麟重置密码

桌面版银河麒麟重置密码 1.选择界面按e 出现银河麒麟系统选择的页面,我们点击键盘上的“e”键,进入电脑启动项编辑页 2.编辑启动页 在启动项编辑页面,我们将光标移动到linux这一行的最后,然后输入“init/bin/bash consoletty0”…

数据结构和算法 - 前置扫盲

数据结构和算法 一、前置扫盲 1、数据结构分类 1.1 逻辑结构:线性与非线性 tip:逻辑结构揭示了数据元素之间的逻辑关系。 线性数据结构:元素间存在明确的顺序关系。 数据按照一定顺序排列,其中元素之间存在一个对应关系&#x…

office办公技能|ppt插件使用

PPT插件获取:链接:https://pan.baidu.com/s/1BOmPioUKeY2TdC-1V-o3Vw 提取码:tdji 一、ppt插件介绍 PPT插件是一种可以帮助用户在Microsoft PowerPoint软件中添加各种额外功能和效果的应用程序。使用PPT插件可以让用户更加轻松地制作出专业、…

探索低代码的潜力、挑战与未来展望

低代码开发作为一种新兴的开发方式,正在逐渐改变着传统的编程模式,低代码使得开发者无需编写大量的代码即可快速构建各种应用程序。然而,低代码也引发了一系列争议,有人称赞其为提升效率的利器,也有人担忧其可能带来的…

【C语言:动态内存管理】

文章目录 前言1.malloc2.free3.calloc4.realloc5.动态内存常见错误6.动态内存经典笔试题分析7.柔性数组8.C/C中的内存区域划分 前言 文章的标题是动态内存管理,那什么是动态内存管理?为什么有动态内存管理呢? 回顾一下以前学的知识&#xff…

西班牙语 Alt 代码表

西班牙语 Alt 代码表,请参考下图。 输入方法就是按住 Alt 键不松开,然后在小键盘上输入字符,松开 Alt 键,计算机就能输出上面的字符了。 西班牙语的字符没有法语和德语的多。 西班牙语 Alt 代码表 - 系统容器 - iSharkFly西班牙语…

Visual Studio Code (Vscode)配置LaTeX

Visual Studio Code (Vscode)配置LaTeX 实操记录 第一步高效检索,找到官方的、靠谱的安装教程,最好多找几个,英文、中文教程都需要 LaTeX WorkshopInstallation and basic settingsHow to install LaTeX (with previews & autocomplete…

(开源)2023工训大赛智能垃圾分类项目(可循环播放视频,显示垃圾分类信息,拍照识别,垃圾分类,满载报警,压缩)

省赛:由于这个比赛是两年一届,并未做足充分的准备,但是通过一定的单片机基础,加上速成能力,也就是熬夜学,通过疯狂的网络搜索,在省赛第5 入选国赛 下面来简单介绍一下我们作品: 主控&#xff1…