系统学习Python——并发模型和异步编程:基础知识

分类目录:《系统学习Python》总目录


并行是并发的一种特殊情况。**所有并行系统都是并发的,但不是所有并发系统都是并行的。**在21世纪初,我们可以使用单核设备在GNU Linux上同时处理100个进程。一台拥有4个CPU核的现代笔记本计算机,在正常情况下,任何时间段内运行的进程数随随便便都会超过200个。如果并行执行200个任务,则需要200个核。因此,多数计算实际是并发的,而不是并行的。操作系统管理着数百个进程,确保每个进程都有机会取得进展,即使CPU本身同时做的事情不能超过4件。

《系统学习Python——并发模型和异步编程》系列文章假定我们事先不具备并发或并行编程知识。我们会简要介绍相关概念之后,将通过简单的示例学习和比较Python为并发编程提供的3个核心包:threadingmultiprocessingasyncio。我们还会讲解增强Python应用性能和伸缩性的第三方工具、库、应用服务器和分布式任务队列。同时,我们也会讲解Python的3种并发方式:线程、进程和原生协程。

导致并发编程困难的因素很多,但我们会讲到启动线程或进程以及如何跟踪线程或进程。调用一个函数,发出调用的代码开始阻塞,直到函数返回。因此,我们知道函数什么时候执行完毕,而且能轻松地得到函数的返回值。如果函数可能抛出异常,则把函数调用放在try/except块中,捕获错误。这些熟悉的概念在我们启动线程或进程后都不可用了。同时,我们无法轻松地得知操作何时结束,若想获取结果或捕获错误,则需要设置某种通信信道,例如消息队列。此外,启动线程或进程有一定消耗,仅仅为了计算一个结果就退出,肯定得不偿失。通常,更好的选择是让各个线程或进程进入一个职程(Worker),循环等待要处理的输入,以此分摊启动成本。但是,这又进一步增加了通信难度,还会引起更多问题。如果不需要职程了,那么如何退出呢?怎样退出才能做到不中断作业,避免留下未处理完毕的数据和未释放的资源(例如打开的文件)呢?同样,解决这些问题通常涉及消息和队列。协程的启动成本很低。使用await关键字启动的协程,返回值容易获取,可以安全取消,捕获异常的位置也明确。但是,协程通常由异步框架启动,因此监控难度与线程或进程相当。

最后,我们还会说明Python协程和线程不适合CPU密集型任务。鉴于此,并发编程需要学习新的概念和编程模式。首先,我们要对核心概念确立统一认识。

术语定义

  • 并发:处理多个待定任务,一次处理一个或并行处理多个(如果条件允许)​,直到所有任务最终都成功或失败。对于单核CPU,如果操作系统的调度程序支持交叉执行待定任务,也能实现并发。并发也叫多任务处理(Multitasking)。
  • 并行:同时执行多个计算任务的能力。需要一个多核CPU、多个CPU、一个GPU或一个集群中的多台计算机。
  • 执行单元:并发执行代码的对象的统称,每个对象的状态和调用栈是独立的。Python原生支持3种执行单元:进程、线程和协程。
  • 进程:计算机程序运行时的一个实例,消耗内存和部分CPU时间。现代桌面操作系统通常同时管理数百个进程,每个进程都隔离在自己的私有内存空间中。进程通过管道、套接字或内存映射文件进行通信—这些方式都只能携带原始字节。Python对象必须序列化(转换)为原始字节才能从一个进程传递到另一个进程。这个过程耗费资源,而且不是所有Python对象都可以序列化。**进程可以派生子进程,子进程彼此之间以及与父进程之间是隔离的。**进程支持抢占式多任务处理机制:操作系统调度程序定期抢占(挂起)运行中的进程,让其他进程运行。这意味着冻结的进程理论上不会冻结整个系统。
  • 线程:单个进程中的执行单元。**一个进程启动后,只使用一个线程,即主线程。通过调用操作系统API,进程可以创建更多线程,执行并发操作。**一个进程内的线程共享相同的内存空间(存储活动的Python对象)​。因此,线程之间可以轻松地共享数据,但是如果多个线程同时更新同一个对象,则可能导致数据损坏。与进程一样,线程在操作系统调度程序的监督下也可以实现抢占式多任务处理。对于同一份作业,线程消耗的资源比进程少。
  • 协程:可以挂起自身并在以后恢复的函数。在Python中,经典协程由生成器函数构建,原生协程使用async def定义。我们在已经《系统学习Python》之前的文章中介绍过经典协程,原生协程的用法将在《系统学习Python——并发模型和异步编程》系列文章中讨论。Python协程通常在事件循环(也在同一个线程中)的监督下在单个线程中运行。asyncioCurioTrio等异步编程框架为基于协程的非阻塞I/O提供了事件循环和支持库。协程支持协作式多任务处理:一个协程必须使用yieldawait关键字显式放弃控制权,另一个协程才可以并发(而非并行)开展工作。这意味着,协程中只要有导致阻塞的代码,事件循环和其他所有协程的执行就都会受到阻塞,这一点与进程和线程的抢占式多任务处理形成鲜明对比。另外,对于同一份作业,协程消耗的资源比线程或进程少。
  • 队列:一种数据结构,可以放入和取出项,顺序通常是先入先出(FIFO)。独立的执行单元可以通过队列交换应用数据和控制消息,例如错误代码和终止信号。队列的实现因底层并发模型而异:Python标准库中的queue包提供的队列类支持线程,multiprocessingasyncio包则实现了其他队列类。queueasyncio包中还有非先入先出队列:LifoQueuePriorityQueue
  • 锁:一种供执行单元用来同步操作和避免数据损坏的对象。更新共享数据结构时,当前代码应持有相关的锁,并告诉程序的其他部分等到锁被释放后再访问这个数据结构。最简单的锁是互斥锁。锁的实现取决于底层并发模型。
  • 争用:对有限资源的争夺。当多个执行单元尝试访问共享资源(例如锁或存储器)时,就会发生资源争用。当计算密集型进程或线程必须等待操作系统调度程序为其分配CPU时间时,还会发生CPU争用。

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.
[2] 卢西亚诺·拉马略.流畅的Python 第2版(全2册) 编程语言[M].人民邮电出版社,2023.

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

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

相关文章

睿尔曼系列机器人——以创新驱动未来,重塑智能协作新生态(下)

在智能制造与人工智能深度融合的当下,机器人技术正经历从 “功能替代” 到 “价值共创” 的深刻跃迁。睿尔曼,作为全球超轻量仿人机械臂领域的先行者,始终秉持 “让机器人触手可及” 的使命,凭借底层技术的突破性进展,…

表征工程(Representation Engineering, RepE)

表征工程(Representation Engineering, RepE) 近年来,表征工程(Representation Engineering, RepE)在提升AI系统透明度和可控性方面取得了显著进展。 一、大模型可解释性与可控性的突破 核心论文:《Representation Engineering: A Top-Down Approach to AI Transparen…

国产ARM+FPGA工业开发平台——GM-3568JHF

一、引言 随着物联网和国产替代需求的快速发展,嵌入式系统面临计算性能与硬件灵活性的双重挑战。GM-3568JHF开发板基于国产“ARMFPGA”异构架构,结合瑞芯微RK3568J处理器与紫光同创Logos-2 FPGA芯片,支持国产自主操作系统,满足通…

RISCV Linux 虚拟内存精讲系列一 Sv39

笔者认为,Linux 操作系统(Operating System)最核心的机制是虚拟内存(Virtual Memory)。因为,操作系统主要作用是将硬件环境抽象起来,给在其中运行的应用(Applications)提…

【apply from: “$flutterRoot/packages/flutter_tools/gradle/flutter.gradle“作用】

这行代码的作用是将 Flutter 的 Gradle 构建脚本集成到 Android 项目中,具体细节如下:作用解析:引入 Flutter 构建逻辑 flutter.gradle 是 Flutter SDK 的核心构建脚本,它负责: 编译 Dart 代码为原生二进制文件&#x…

深入理解JavaScript设计模式之命令模式

深入理解JavaScript设计模式之命令模式 文章目录深入理解JavaScript设计模式之命令模式定义简单命令模式组合命令模式使用命令模式实现文本编辑器目标关键类说明实现的效果交互逻辑流程所有代码:总结定义 命令模式也是设计模式种相对于变焦简单容易理解的一种设计模…

CSS 网页布局:从基础到进阶

CSS 网页布局:从基础到进阶 引言 随着互联网的飞速发展,网页设计已经成为了一个不可或缺的领域。CSS(层叠样式表)作为网页设计中的关键工具,用于控制网页元素的样式和布局。本文将为您全面解析CSS网页布局,…

【人工智能】大语言模型(LLM) NLP

大语言模型(LLM)& NLP1.大语言模型(LLM)1.1 一句话解释1.2 更形象的比喻1.3 为什么叫 “大” 模型1.4 它能做什么1.5 现实中的例子2.对比 NLP2.1 用 “汽车进化” 比喻 NLP → LLM2.2 为什么说 LLM 属于 NLP2.3 LLM 的 “革命…

Unity HDRP + Azure IoT 的 Python 后端实现与集成方案

Unity HDRP Azure IoT 的 Python 后端实现与集成方案 虽然Unity HDRP本身使用C#开发,但我们可以构建Python后端服务支持物联网系统,并与Unity引擎深度集成。以下是完整的实现方案: 系统架构 #mermaid-svg-qCDb0g9Ik287Cg8X {font-family:&qu…

小黑黑日常积累大模型prompt句式2:【以段落的形式输出,不分点列举】【如果没有相关内容则不输出】【可读性强】【输出格式规范】

以段落的形式输出,不分点列举 每个标题下直接接续段落内容,不编号、不分点。......标题下直接接续段落内容,不继续进行分点列举。如果没有相关内容则不输出 若某一部分无法从原文中提取有效信息,则跳过该部分内容,不做…

React Native 基础组件详解<一>

一、Text组件 1)numberOfLines:显示行数 2)ellipsizeMode:超出隐藏的位置 clip->裁掉 head/middle/ tail->点的位置 3)selectable: 是否可以选中 4)selectionColor:选中后的颜色 5&#…

异步编程(Promise/Generator/async)

1、Promise 2、Generator 3、async/await

【Note】《Kafka: The Definitive Guide》 第8章: Cross-Cluster Data Mirroring

《Kafka: The Definitive Guide》 第8章: Cross-Cluster Data Mirroring 一、跨集群镜像的场景与价值 多区域低延迟访问 将业务数据从主集群实时复制到多个地理区域的集群,缩短消费者跨区读取延迟。 灾备切换 当主集群出现故障时,可快速将消…

「Windows/Mac OS」AIGC图片生成视频 ,webui + stable-diffusion环境部署教程

stable-diffusion webui 环境搭建目录 一、Windows 环境部署 stable-diffusion-webui1、准备条件2、安装Python 3.10.X(**较新版本的 Python 不支持 torch**)3、安装Git 教程4、使用Git 下载 stable-diffusion-webui 存储库,4.1、显示报错 5…

【深度学习】 深度学习训练配置参数详解

深度学习训练配置参数详解 1. 启动初始化参数说明CUDA_VISIBLE_DEVICES指定使用的GPU设备编号("0"表示单卡)seed随机种子(1777777),保证实验可复现性cuda是否启用GPU加速(True)benchm…

期望,积分,均值,求和的关系

1. 回顾期望的定义 对于连续性随机变量 X X X,期望为: E X ∼ f ( x ) [ X ] ∫ Ω x f ( x ) d x E_{X\sim f(x)}[X] \int_{\Omega}xf(x)dx EX∼f(x)​[X]∫Ω​xf(x)dx 其中 f ( x ) f(x) f(x)为概率密度函数, Ω \Omega Ω为概率密度函…

1.如何对多个控件进行高效的绑定 C#例子 WPF例子

使用ObservableCollection高效为多个控件绑定数据在WPF开发中,数据绑定是一个非常重要的功能,它允许我们将UI控件与数据源进行绑定,从而实现数据的自动更新。当需要为多个控件绑定数据时,使用ObservableCollection可以大大提高开发…

JSONLines和JSON数据格式使用教程

文章目录 一、核心区别二、JSONLines 的优势三、Python 中使用 JSONLines1. 写入 JSONLines 文件2. 读取 JSONLines 文件3. 处理大文件示例四、常见工具支持1. 命令行工具2. 编程语言库五、适用场景选择六、注意事项总结JSONLines(简称 jsonl 或 jl)和传统 JSON 都是用于存储…

链表算法之【反转链表】

目录 LeetCode-206题 LeetCode-206题 给定一个单链表的头节点,请反转链表,并返回反转后的链表 class Solution {public ListNode reverseList(ListNode head) {// checkif (head null || head.next null)return head;// 双指针ListNode p1 head;Li…

回溯题解——子集【LeetCode】输入的视角(选或不选)

78. 子集 ✅ 一、算法逻辑讲解(逐步思路) 逻辑讲解: dfs(i):表示从下标 i 开始,做“选 or 不选”的子集构造。 终止条件 if i n: 到达数组末尾,表示一种完整子集构造完成。 把当前构造路径…