Python 中的并发 - 简介
在本章中,我们将了解Python中并发的概念,并了解不同的线程和进程。
什么是并发?
简单来说,并发就是两个或多个事件同时发生。并发是一种自然现象,因为许多事件在任何给定时间同时发生。
在编程方面,并发是指两个任务在执行中重叠。通过并发编程,我们的应用程序和软件系统的性能可以得到提高,因为我们可以并发处理请求,而不是等待前一个请求完成。
并发的历史回顾
以下几点将为我们简要回顾并发的历史 -
从铁路的概念来看
并发性与铁路的概念密切相关。对于铁路,需要在同一铁路系统上处理多列火车,以便每列火车都能安全到达目的地。
学术界的并发计算
人们对计算机科学并发性的兴趣始于 Edsger W. Dijkstra 于 1965 年发表的研究论文。在这篇论文中,他发现并解决了并发控制的互斥问题。
高级并发原语
最近,由于高级并发原语的引入,程序员正在获得改进的并发解决方案。
提高编程语言的并发性
Google 的 Golang、Rust 和 Python 等编程语言在帮助我们获得更好的并发解决方案的领域取得了令人难以置信的发展。
什么是线程和多线程?
线程是操作系统中可以执行的最小执行单元。它本身不是程序,而是在程序内运行。换句话说,线程并不是相互独立的。每个线程与其他线程共享代码部分、数据部分等。它们也被称为轻量级流程。
线程由以下组件组成 -
程序计数器由下一条可执行指令的地址组成
堆
寄存器组
唯一的ID
另一方面,多线程是 CPU 通过同时执行多个线程来管理操作系统使用的能力。多线程的主要思想是通过将一个进程划分为多个线程来实现并行性。可以借助以下示例来理解多线程的概念。
例子
假设我们正在运行一个特定的进程,其中我们打开 MS Word 以在其中键入内容。将分配一个线程来打开 MS Word,并要求另一个线程在其中键入内容。现在,如果我们想要编辑现有的,则需要另一个线程来完成编辑任务等等。
什么是进程和多重处理?
流程被定义为一个实体,它代表系统中要实现的基本工作单元。简而言之,我们将计算机程序编写在文本文件中,当我们执行该程序时,它就成为执行程序中提到的所有任务的进程。在进程生命周期中,它会经历不同的阶段——启动、就绪、运行、等待和终止。
下图显示了流程的不同阶段 -
一个进程只能有一个线程(称为主线程),也可以有多个线程(有自己的一组寄存器、程序计数器和堆栈)。下图将向我们展示差异 -
另一方面,多处理是在单个计算机系统中使用两个或多个 CPU 单元。我们的主要目标是充分发挥硬件的潜力。为了实现这一目标,我们需要利用计算机系统中可用的全部 CPU 核心。多处理是做到这一点的最佳方法。
Python 是最流行的编程语言之一。以下是使其适合并发应用程序的一些原因 -
语法糖
语法糖是编程语言中的语法,旨在使内容更易于阅读或表达。它使语言对于人类使用来说变得“更甜蜜”:事物可以更清晰、更简洁地表达,或者根据偏好以其他风格表达。Python 附带了 Magic 方法,可以定义这些方法来作用于对象。这些 Magic 方法被用作语法糖,并绑定到更易于理解的关键字。
大型社区
Python 语言在人工智能、机器学习、深度学习和定量分析领域的数据科学家和数学家中得到了广泛的采用。
用于并发编程的有用 API
Python 2 和 3 有大量专用于并行/并发编程的 API。其中最流行的是线程、concurrent.features、multiprocessing、asyncio、gevent 和 greenlet等。
Python 在实现并发应用程序方面的局限性
Python 对并发应用程序有限制。Python 中存在这种限制,称为GIL(全局解释器锁) 。GIL 不允许我们利用 CPU 的多个核心,因此我们可以说 Python 中不存在真正的线程。我们可以这样理解GIL的概念:
GIL(全局解释器锁)
它是 Python 世界中最具争议的话题之一。在 CPython 中,GIL 是互斥锁 - 互斥锁,它使事物成为线程安全的。换句话说,我们可以说 GIL 阻止了多个线程并行执行 Python 代码。锁一次只能由一个线程持有,如果我们想要执行一个线程,那么它必须首先获取锁。下图将帮助您了解 GIL 的工作原理。
然而,Python 中有一些库和实现,例如Numpy、Jpython和IronPytbhon。这些库无需与 GIL 进行任何交互即可工作。