Python 中的并发 - 线程

一般来说,我们知道线是一种非常细的扭线,通常由棉或丝织物制成,用于缝制衣服等。在计算机编程领域也使用相同的术语"线"。现在,我们如何将用于缝制衣服的线与用于计算机编程的线联系起来?这两种线在这里所起的作用是相似的。在衣服中,线将布料固定在一起,另一方面,在计算机编程中,线固定计算机程序并允许程序执行连续操作或同时执行多个操作。

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

线程状态

要深入了解线程的功能,我们需要了解线程的生命周期或不同的线程状态。通常,一个线程可以存在于五种不同的状态中。不同的状态如下所示 −

新线程

新线程在新状态下开始其生命周期。但是,在此阶段,它尚未启动,也未分配任何资源。我们可以说它只是一个对象的实例。

可运行

随着新线程的启动,该线程变为可运行状态,即等待运行。在此状态下,它拥有所有资源,但任务调度程序仍未安排它运行。

正在运行

在此状态下,线程取得进展并执行任务调度程序选择运行的任务。现在,线程可以进入死亡状态或非运行/等待状态。

非运行/等待

在此状态下,线程暂停,因为它正在等待某些 I/O 请求的响应或等待其他线程的执行完成。

死亡

当可运行线程完成其任务或以其他方式终止时,它将进入终止状态。

下图显示了线程的完整生命周期 −

Dead

线程类型

在本节中,我们将了解不同类型的线程。这些类型如下所述 −

用户级线程

这些是用户管理的线程。

在这种情况下,线程管理内核不知道线程的存在。线程库包含用于创建和销毁线程、在线程之间传递消息和数据、调度线程执行以及保存和恢复线程上下文的代码。应用程序以单个线程启动。

用户级线程的示例是 −

  • Java 线程
  • POSIX 线程
Dead

用户级线程的优势

以下是用户级线程的不同优势 −

  • 线程切换不需要内核模式权限。
  • 用户级线程可以在任何操作系统上运行。
  • 在用户级线程中,调度可以是特定于应用程序的。
  • 用户级线程的创建和管理速度很快。

用户级线程的缺点

以下是用户级线程的不同缺点 −

  • 在典型的操作系统中,大多数系统调用都是阻塞的。
  • 多线程应用程序无法利用多处理。

内核级线程

操作系统管理的线程作用于内核,即操作系统核心。

在这种情况下,内核进行线程管理。应用程序区域中没有线程管理代码。内核线程由操作系统直接支持。任何应用程序都可以编程为多线程。应用程序中的所有线程都在单个进程中受支持。

内核维护整个进程以及进程内各个线程的上下文信息。内核的调度是基于线程进行的。内核在内核空间中执行线程创建、调度和管理。内核线程的创建和管理通常比用户线程慢。内核级线程的示例有 Windows、Solaris。

Dead

内核级线程的优势

以下是内核级线程的不同优势 −

  • 内核可以同时在多个进程上调度来自同一进程的多个线程。

  • 如果进程中的一个线程被阻塞,内核可以调度同一进程的另一个线程。

  • 内核例程本身可以是多线程的。

内核级线程的缺点

  • 内核线程的创建和管理通常比用户线程慢。

  • 在同一进程内将控制权从一个线程转移到另一个线程需要切换到内核模式。

线程控制块 - TCB

线程控制块 (TCB) 可以定义为操作系统内核中的数据结构,主要包含有关线程的信息。存储在 TCB 中的线程特定信息将突出显示有关每个进程的一些重要信息。

考虑以下与 TCB 中包含的线程相关的要点 −

  • 线程标识 − 它是分配给每个新线程的唯一线程 ID (tid)。

  • 线程状态 − 它包含与线程状态(运行、可运行、非运行、死亡)相关的信息。

  • 程序计数器 (PC) − 它指向线程的当前程序指令。

  • 寄存器集 − 它包含分配给它们用于计算的线程寄存器值。

  • 堆栈指针 − 它指向进程中的线程堆栈。它包含线程范围内的局部变量。

  • 指向 PCB 的指针 −它包含指向创建该线程的进程的指针。

pcb

进程与线程之间的关系

在多线程中,进程和线程是两个非常密切相关的术语,它们具有相同的目标,即使计算机能够同时执行多件事。进程可以包含一个或多个线程,但相反,线程不能包含进程。但是,它们仍然是两个基本执行单元。程序执行一系列指令,启动进程和线程。

下表显示了进程和线程之间的比较 −

进程 线程
进程是重量级的或资源密集型的。 线程是轻量级的,比进程占用更少的资源。
进程切换需要与操作系统交互。 线程切换不需要与操作系统交互。
在多处理环境中,每个进程执行相同的代码,但拥有自己的内存和文件资源。 所有线程都可以共享同一组打开的文件、子进程。
如果一个进程被阻塞,则在第一个进程解除阻塞之前,其他进程都无法执行。 当一个线程被阻塞并等待时,同一个进程中的第二个线程任务可以运行。
不使用线程的多个进程使用更多资源。 多线程进程使用更少的资源。
在多个进程中,每个进程独立于其他进程运行。 一个线程可以读取、写入或更改另一个线程的数据。
如果父进程发生任何变化,则不会影响子进程。 如果主线程发生任何变化,则可能会影响该进程的其他线程的行为。
要与兄弟进程通信,进程必须使用进程间通信。 线程可以直接与该进程的其他线程通信。

多线程概念

正如我们之前讨论过的,多线程是 CPU 通过并发执行多个线程来管理操作系统使用的能力。多线程的主要思想是通过将进程分成多个线程来实现并行性。更简单地说,多线程就是利用线程的概念来实现多任务处理的方式。

通过以下示例可以理解多线程的概念。

示例

假设我们正在运行一个进程。该进程可能用于打开 MS Word 进行书写。在此进程中,将分配一个线程来打开 MS Word,并需要另一个线程进行书写。现在,假设我们想要编辑某些内容,则需要另一个线程来执行编辑任务,依此类推。

下图可帮助我们理解内存中如何存在多个线程。 −

多线程

我们可以在上图中看到,一个进程中可以存在多个线程,每个线程都包含自己的寄存器集和局部变量。除此之外,进程中的所有线程都共享全局变量。

多线程的优点

现在让我们看看多线程的一些优点。优点如下 −

  • 通信速度 − 多线程提高了计算速度,因为每个核心或处理器同时处理单独的线程。

  • 程序保持响应 − 它允许程序保持响应,因为一个线程等待输入,另一个线程同时运行 GUI。

  • 访问全局变量 −在多线程中,特定进程的所有线程都可以访问全局变量,如果全局变量有任何变化,其他线程也可以看到它。

  • 资源利用 − 每个程序中运行多个线程可以更好地利用 CPU,CPU 的空闲时间会减少。

  • 数据共享 − 每个线程不需要额外的空间,因为程序中的线程可以共享相同的数据。

多线程的缺点

现在让我们看看多线程的一些缺点。缺点如下 −

  • 不适合单处理器系统 − 与多处理器系统相比,多线程在单处理器系统上很难实现计算速度方面的性能。

  • 安全问题 − 众所周知,程序中的所有线程共享相同的数据,因此始终存在安全问题,因为任何未知线程都可以更改数据。

  • 增加复杂性 − 多线程会增加程序的复杂性,调试变得困难。

  • 导致死锁状态 − 多线程可能导致程序面临达到死锁状态的潜在风险。

  • 需要同步 − 需要同步以避免互斥。这会导致更多的内存和 CPU 利用率。