Day05: Python 中的并发和并行(1)

理解 Python 中的线程和进程

理解线程和进程是实现在 Python 中并发和并行的基础。这种知识使你能够编写能够看似同时执行多个任务的程序,从而提高性能和响应能力。本课程将深入探讨线程和进程的核心概念、它们的区别,以及它们如何为更高级的并发技术奠定基础。

线程:轻量级并发

线程是同一进程内的独立执行路径。它们共享相同的内存空间,这使得它们能够轻松访问和修改相同的数据。这种共享内存模型使得线程间的通信相对简单,但也引入了竞态条件和其它同步问题的风险。

线程的概念

线程可以被视为一个轻量级子进程。操作系统管理线程,允许它们并发运行。当一个线程正在等待资源或执行阻塞操作(如 I/O)时,操作系统可以切换到另一个线程,使 CPU 保持忙碌。

示例: 想象一个文字处理器。一个线程可能处理用户输入,另一个线程可能在后台执行拼写检查,还有一个线程可能定期自动保存文档。所有这些线程都在同一个文字处理器应用程序(进程)中运行。

线程的优点

  • 轻量级: 创建和销毁线程通常比创建和销毁进程更快,并且消耗更少的资源。
  • 共享内存: 同一进程内的线程可以轻松共享数据,简化了通信和数据交换。
  • 响应性: 多线程可以通过允许应用程序在某个线程被阻塞时继续执行其他任务来提高其响应性。

线程的缺点

  • 全局解释器锁 (GIL): 在 CPython 中,标准的 Python 解释器,GIL 允许在任何给定时间只有一个线程持有对 Python 解释器的控制权。这限制了多线程 Python 程序中 CPU 密集型任务的真实并行性。然而,I/O 密集型任务仍然可以从多线程中受益,因为当线程等待 I/O 时 GIL 会被释放。
  • 同步问题: 由于线程共享内存,如果不同步,它们可能会相互干扰。这可能导致竞态条件、死锁和其他并发问题。
  • 调试复杂性: 由于线程执行的不可确定性,调试多线程程序可能比调试单线程程序更具挑战性。

线程的实际示例

  1. Web Server: Web 服务器可以使用多个线程来并发处理传入的客户端请求。每个线程可以独立地处理一个请求,使服务器能够同时服务多个客户端。
  2. 图形界面应用程序: 图形界面应用程序通常使用线程来保持用户界面的响应性。例如,一个单独的线程可以处理长时间运行的任务,如下载文件,而不会阻塞主 UI 线程。
  3. 数据处理: 数据处理应用程序可以使用线程来并发处理不同的数据块,从而加快整体处理时间。

代码示例:基本线程

import threading
import timedef task(name):print(f"Thread {name}: Starting")time.sleep(2)  # Simulate a time-consuming taskprint(f"Thread {name}: Finishing")# 创建并启动多个线程
threads = []
for i in range(3):t = threading.Thread(target=task, args=(f"Thread-{i+1}",))threads.append(t)t.start()# 等待所有线程完成
for t in threads:t.join()print("所有线程完成")

解释:

  • threading 模块被导入以处理线程。
  • task 函数使用 time.sleep() 模拟耗时操作。
  • 创建了三个线程,每个线程以不同的名称运行 task 函数。
  • t.start() 启动每个线程。
  • t.join() 会等待每个线程完成后再继续主程序。

进程:独立执行

进程是并发运行的独立程序。每个进程都有自己独立的内存空间,这意味着进程不能直接共享数据。进程之间的通信需要进程间通信(IPC)机制,例如管道、套接字或共享内存。

进程的概念

进程是一个正在执行的程序的实例。操作系统为每个进程分配资源,例如内存和 CPU 时间。进程之间是相互隔离的,这意味着一个进程不能直接访问另一个进程的内存或资源。

示例: 考虑运行两个文本编辑器实例。每个实例是一个独立进程,拥有自己的内存空间和资源。如果一个实例崩溃,它不会影响另一个实例。

进程的优势

  • 真正的并行性: 进程可以在多核处理器上实现真正的并行性,因为每个进程都有自己的解释器和内存空间,从而绕过了 GIL 的限制。
  • 隔离: 进程彼此隔离,这意味着一个进程的崩溃不会影响其他进程。
  • 安全: 进程隔离通过防止一个进程访问或修改其他进程的数据来增强安全性。

进程的缺点

  • 开销: 创建和销毁进程通常比创建和销毁线程更耗费资源。
  • 进程间通信(IPC): 进程间的通信需要 IPC 机制,这比线程间的共享内存通信可能更复杂且更慢。
  • 内存占用: 每个进程都有自己的内存空间,与多线程应用程序相比,这可能导致更大的内存占用。

进程的实际案例

  1. 视频编码: 一个视频编码应用程序可以使用多个进程同时编码视频的不同片段,显著减少编码时间。
  2. 科学计算: 科学计算应用通常使用多个进程来并行执行复杂的计算,利用多核处理器的强大功能。
  3. 分布式系统: 分布式系统使用运行在不同机器上的多个进程来并行执行任务,并提供高可用性和可扩展性。

代码示例:基本多进程

import multiprocessing
import timedef task(name):print(f"Process {name}: Starting")time.sleep(2)  # 模拟耗时的任务print(f"Process {name}: Finishing")if __name__ == "__main__":# 创建并启动多个进程processes = []for i in range(3):p = multiprocessing.Process(target=task, args=(f"Process-{i+1}",))processes.append(p)p.start()# 等待所有进程完成for p in processes:p.join()print("所有进程完成")

解释:

  • multiprocessing 模块被导入以处理进程。
  • task 函数使用 time.sleep() 模拟耗时操作。
  • 创建了三个进程,每个进程都运行不同的 task 函数。
  • p.start() 启动每个进程。
  • p.join() 会等待每个进程完成后再继续主程序。
  • if __name__ == "__main__": 代码块是必要的,以防止在某些操作系统上子进程递归地创建新进程。

线程与进程:主要区别

特性线程进程
内存空间共享独立
资源消耗轻量级重量级
并行性受 GIL(在 CPython 中)限制多核 CPU 上的真正并行
隔离
通信共享内存,更容易实现IPC 机制,更复杂
上下文切换更快更慢
碰撞影响一个线程崩溃会影响整个进程一个进程崩溃不会影响其他进程

在线程和进程之间进行选择

  • I/O 密集型任务: 对于 I/O 密集型任务,线程通常是较好的选择,因为程序大部分时间都在等待 I/O 操作完成。当线程等待 I/O 时,GIL 会被释放,允许其他线程运行。
  • CPU 密集型任务: 对于 CPU 密集型任务,进程通常是更好的选择,因为程序大部分时间都在进行计算。进程可以在多核处理器上实现真正的并行性,绕过 GIL 的限制。
  • 隔离: 如果隔离是一个关键要求,进程是首选的选择。
  • 复杂性: 线程通常比进程更容易实现和管理,尤其是在共享数据方面。

实际应用

考虑一个大规模数据处理流程。该流程包含多个阶段,如数据采集、数据清洗、数据转换和数据分析。线程和进程都可以用来并行化该流程,但选择取决于所涉及任务的性质。

  • 数据采集: 如果数据采集涉及从多个网络源读取数据(I/O 密集型),可以使用线程来同时处理多个连接。
  • 数据清洗和转换: 如果数据清洗和转换涉及 CPU 密集型操作,例如复杂的计算或字符串操作,可以使用进程来利用多个核心,实现真正的并行处理。
  • 数据分析: 根据分析的复杂性,可以使用线程或进程。对于简单的分析任务,线程可能就足够了。对于更复杂的数据分析任务,可能需要使用进程来达到最佳性能。

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

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

相关文章

Spring Boot 集成 MinIO 实现分布式文件存储与管理

Spring Boot 集成 MinIO 实现分布式文件存储与管理 一、MinIO 简介 MinIO 是一个高性能的分布式对象存储服务器,兼容 Amazon S3 API。它具有以下特点: 轻量级且易于部署高性能(读写速度可达每秒数GB)支持数据加密和访问控制提供…

从小白入门,基于Cursor开发一个前端小程序之Cursor 编程实践与案例分析

Cursor 编程实践与案例分析 Cursor 编程实践与案例分析 1. 什么是 Cursor? Cursor 是一款面向开发者的 AI 编程助手,集成于本地 IDE,支持自然语言与代码的无缝协作。它不仅能自动补全、重构、查找代码,还能理解业务上下文&#…

一、如何用MATLAB画一个三角形 代码

一、如何用MATLAB画一个三角形 代码在MATLAB中绘制三角形可以通过指定三个顶点的坐标并使用 fill 或 patch 函数实现。以下是详细代码示例:方法1:使用 fill 函数(简单填充)% 定义三角形的三个顶点坐标 (x, y) x [0, 1, 0.5]; % …

Postman自动化测试提取相应body体中的参数

文章目录Postman自动化测试提取相应body体中的参数1. 示例响应 Body 参数2. 提取响应 Body 参数Postman自动化测试提取相应body体中的参数 上一篇的文中介绍了使用postman自动化测试时从响应的header中提取token参数,很多同学私信问如何从响应体body中提取参数。 有…

vue-39(为复杂 Vue 组件编写单元测试)

实际练习:为复杂 Vue 组件编写单元测试 单元测试对于确保复杂 Vue 组件的可靠性和可维护性至关重要。通过隔离和测试代码的各个单元,您可以在开发过程的早期发现并修复错误,从而构建更健壮和可预测的应用程序。本课程重点介绍为复杂 Vue 组件编写单元测试的实用方面,建立在…

c语言中的函数IV

函数的先后关系 直接把函数放在程序上方是可以的 在实际开发中,我们更希望把main函数放在前面 这样子直接把自己定义的函数放在main函数下方,编译会出现warning和error正确的解决方案是:把函数的头放到main函数上方,这样就能正常…

大模型Decoder-Only深入解析

Decoder-Only整体结构 我们以模型Llama-3.1-8B-Instruct为例,打印其结构如下(后面会慢慢解析每一部分,莫慌): LlamaForCausalLM((model): LlamaModel((embed_tokens): VocabParallelEmbedding(num_embeddings128256,…

web网页,在线%电商,茶叶,商城,网上商城系统%分析系统demo,于vscode,vue,java,jdk,springboot,mysql数据库

经验心得 这也是帮之前一客户加了几个功能,需要掌握crud,前后端开发,前后端怎么对接,前后端通讯是以那种格式,把这些掌握后咱们就可以进行网站开发了。后端记好一定要分层开发,不要像老早一起所有代码写到一…

MybatisPlus-05.核心功能-条件构造器

一.条件构造器 我们前面使用的MP功能主要是根据id进行操作的,并未涉及到复杂查询。而根据id所进行的增删改查操作在MP中都有直接的封装。但是遇到复杂的查询条件时,如何使用MP进行操作是我们要考虑的问题。因此MP为我们提供了条件构造器。 在BaseMapper…

ES6从入门到精通:常用知识点

变量声明ES6引入了let和const替代var。let用于声明可变的块级作用域变量,const用于声明不可变的常量。块级作用域有效避免了变量提升和污染全局的问题。let name Alice; const PI 3.1415;箭头函数箭头函数简化了函数写法,且自动绑定当前上下文的this值…

51单片机教程(十一)- 单片机定时器

11、单片机定时器 项目目标 通过定时器/计数器实现流水灯控制。知识要点 定时器的结构。TMOD和TCON;定时/计数器工作方式;定时/计数器编程步骤;1、项目分析 前面的流水灯的时间控制通过空循环语句来实现,定时不是很精确。本章通过用定时器来控制流水灯任务可以实现精确的时…

基于opencv的疲劳驾驶监测系统

博主介绍:java高级开发,从事互联网行业多年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经做了多年的毕业设计程序开发,开发过上千套毕业设计程序,没有什么华丽的语言&#xff0…

Vue 2 和 Vue 3 区别

1. 响应式系统原理 Vue 2:利用Object.defineProperty()实现属性拦截。存在局限性,无法自动监测对象属性增减,需用Vue.set/delete;数组变异方法要重写;深层对象递归转换性能差。Vue 3:采用 ES6 Proxy代理对…

mv重命名报错:-bash:syntax error near unexpected token ‘(‘

文章目录 一、报错背景二、解决方法2.1、方法一:文件名加引号2.2、方法二:特殊字符前加\进行转义 一、报错背景 在linux上对一文件执行重命名时报错。原因是该文件名包含空格与括号。 文件名如下: aa (1).txt执行命令及报错如下…

AWS 开源 Strands Agents SDK,简化 AI 代理开发流程

最近,亚马逊网络服务(AWS)宣布推出 Strands Agents(https://github.com/strands-agents/sdk-python),这一开源软件开发工具包(SDK)采用模型驱动的方法,助力开发者仅用数行代码即可构建并运行人工…

利用 AI 打造的开发者工具集合

如图. 我利用 AI 开发了这个网站花了半个小时. 目前就上了 四个 我想到的工具。 大家可以自行体验下:https://xiaojinzi123.github.io 本文并不是宣传什么产品. 只是感概 Ai 真的改变我的工作方式啊. 虽然现在 AI 对于一些已有的项目进行更改代码. 由于不了解业务,…

[自然语言处理]计算语言的熵

一、要求利用给定的中英文语料,分别计算英语字母、英语单词、汉字、汉语词的熵,并和已公开结果比较,思考汉语的熵对汉语编码和处理的影响。二、实验内容2.1 统计英文语料的熵1.代码(1)计算英文字母的熵import math #计算每个英文字母的熵 def…

如何处理“协议异常”错误

在Java中,“协议异常”通常是指在网络通信或者处理特定协议相关操作时出现的异常。以下是一些处理“协议异常”错误的方法:一、理解协议异常的类型和原因HTTP协议异常原因:在进行HTTP通信时,可能会因为请求格式错误、响应状态码异…

Spark 4.0的VariantType 类型以及内部存储

背景 本文基于Spark 4.0 总结 Spark中的 VariantType 类型,用尽量少的字节来存储Json的格式化数据 分析 这里主要介绍 Variant 的存储,我们从VariantBuilder.buildJson方法(把对应的json数据存储为VariantType类型)开始: public static Variant parseJson(JsonParser …

跨越十年的C++演进:C++20新特性全解析

跨越十年的C演进系列,分为5篇,本文为第四篇,后续会持续更新C23~ 前3篇如下: 跨越十年的C演进:C11新特性全解析 跨越十年的C演进:C14新特性全解析 跨越十年的C演进:C17新特性全解析 C20标准…