Python 中的并发 - 简介

在本章中,我们将了解 Python 中的并发概念,并了解不同的线程和进程。

什么是并发?

简而言之,并发是两个或多个事件同时发生。并发是一种自然现象,因为许多事件在任何给定时间同时发生。

就编程而言,并发是指两个任务在执行中重叠。使用并发编程,我们的应用程序和软件系统的性能可以得到改善,因为我们可以同时处理请求,而不是等待前一个请求完成。

并发的历史回顾

以下几点将为我们简要回顾并发的历史−

从铁路的概念开始

并发与铁路的概念密切相关。对于铁路,需要在同一铁路系统上处理多列火车,以便每列火车都能安全到达目的地。

学术界的并发计算

对计算机科学并发的兴趣始于 Edsger W. Dijkstra 于 1965 年发表的研究论文。在这篇论文中,他确定并解决了互斥问题,即并发控制的属性。

高级并发原语

近年来,由于引入了高级并发原语,程序员正在获得改进的并发解决方案。

使用编程语言改进并发

Google 的 Golang、Rust 和 Python 等编程语言在帮助我们获得更好的并发解决方案的领域取得了令人难以置信的发展。

什么是线程和多线程?

线程是操作系统中可以执行的最小执行单元。它本身不是一个程序,而是在程序内运行。换句话说,线程彼此之间并不独立。每个线程与其他线程共享代码部分、数据部分等。它们也称为轻量级进程。

线程由以下组件组成 −

  • 程序计数器,包含下一个可执行指令的地址

  • 堆栈

  • 寄存器集

  • 唯一 ID

另一方面,多线程是 CPU 通过并发执行多个线程来管理操作系统使用的能力。多线程的主要思想是通过将进程划分为多个线程来实现并行性。借助以下示例,可以理解多线程的概念。

示例

假设我们正在运行一个特定的进程,其中我们打开 MS Word 在其中输入内容。一个线程将被分配用于打开 MS Word,另一个线程将需要在其中输入内容。现在,如果我们想要编辑现有的内容,则需要另一个线程来执行编辑任务,依此类推。

什么是进程和多处理?

A进程被定义为一个实体,它代表系统中要实现的基本工作单元。简单地说,我们在文本文件中编写计算机程序,当我们执行这个程序时,它就变成了一个执行程序中提到的所有任务的进程。在进程生命周期中,它会经历不同的阶段——启动、就绪、运行、等待和终止。

下图显示了进程的不同阶段 −

Multiprocessing

一个进程只能有一个线程,称为主线程,或者有多个线程,每个线程都有自己的一组寄存器、程序计数器和堆栈。下图将向我们展示差异 −

Multiprocessing One

另一方面,多处理是在单个计算机系统中使用两个或更多 CPU 单元。我们的主要目标是充分利用硬件的潜力。为了实现这一点,我们需要充分利用计算机系统中可用的全部 CPU 内核。多处理是实现此目标的最佳方法。

Multiprocessing Two

Python 是最流行的编程语言之一。以下是使其适合并发应用程序的一些原因 −

语法糖

语法糖是编程语言中的语法,旨在使事情更易于阅读或表达。它使语言对人类使用"更甜美":可以更清晰、更简洁地表达事物,或根据偏好以其他风格表达事物。Python 附带魔法方法,可以将其定义为对对象起作用。这些魔法方法用作语法糖,并与更易于理解的关键字绑定。

大型社区

Python 语言在数据科学家和数学家中得到了广泛的采用,他们从事人工智能、机器学习、深度学习和定量分析领域的工作。

并发编程的有用 API

Python 2 和 3 拥有大量专用于并行/并发编程的 API。其中最受欢迎的是 threading、concurrent.features、multiprocessing、asyncio、gevent 和 greenlets 等。

Python 在实现并发应用程序方面的局限性

Python 对并发应用程序有限制。此限制称为 GIL(全局解释器锁),存在于 Python 中。GIL 不允许我们使用多个 CPU 核心,因此我们可以说 Python 中没有真正的线程。我们可以这样理解 GIL 的概念 −

GIL(全局解释器锁)

它是 Python 世界中最具争议的话题之一。在 CPython 中,GIL 是互斥锁,它使线程安全。换句话说,我们可以说 GIL 阻止多个线程并行执行 Python 代码。锁一次只能由一个线程持有,如果我们要执行一个线程,那么它必须先获取锁。下图将帮助您了解 GIL 的工作原理。

Limitations

但是,Python 中有一些库和实现,例如 Numpy、JpythonIronPytbhon。这些库无需与 GIL 进行任何交互即可工作。