Python - 并发性线程
一般来说,正如我们所知,线是一种非常细的加捻线,通常由棉或丝绸织物制成,用于缝制衣服等。在计算机编程领域也使用了相同的术语 thread。现在,我们如何将用于缝制衣服的线和用于计算机编程的线联系起来呢?这两个线程执行的角色在这里类似。在衣服中,线将布料固定在一起,而在另一侧,在计算机编程中,线保持计算机程序并允许程序同时执行顺序动作或多个动作。
线程是操作系统中的最小执行单位。它本身不是一个程序,而是在程序中运行。换句话说,线程不是彼此独立的,而是与其他线程共享代码段、数据段等。这些线程也称为轻量级进程。
线程的状态
要深入了解线程的功能,我们需要了解线程的生命周期或不同的线程状态。通常,线程可以以 5 种不同的状态存在。不同的状态如下所示 -
新建线程
新线程以新状态开始其生命周期。但是,在这个阶段,它还没有开始,也没有分配任何资源。我们可以说它只是一个对象的一个实例。
可运行
当新诞生的线程启动时,线程变得可运行,即等待运行。在此状态下,它拥有所有资源,但任务计划程序仍未安排它运行。
运行
在此状态下,线程取得进展并执行任务,任务计划程序已选择运行该任务。现在,线程可以进入 dead 状态或 non-runnable/ waiting 状态。
未运行/等待
在此状态下,线程暂停,因为它正在等待某个 I/O 请求的响应,或者正在等待其他线程的执行完成。
终止
可运行的线程在完成其任务或以其他方式终止时进入 terminated 状态。
下图显示了线程的完整生命周期 -
螺纹类型
在本节中,我们将看到不同类型的线程。类型如下所述 -
用户级线程
这些是用户管理的线程。
在这种情况下,线程管理内核不知道线程的存在。线程库包含用于创建和销毁线程、在线程之间传递消息和数据、调度线程执行以及保存和恢复线程上下文的代码。应用程序从单个线程开始。
用户级别线程的示例包括 -
- Java 线程
- POSIX 线程
用户级线程的优势
以下是用户级别线程的不同优势 -
- 线程切换不需要内核模式权限。
- 用户级线程可以在任何操作系统上运行。
- 调度可以是用户级线程中特定于应用程序的。
- 用户级别的线程可以快速创建和管理。
用户级线程的缺点
以下是用户级线程的不同缺点 -
- 在典型的操作系统中,大多数系统调用都是阻塞的。
- 多线程应用程序无法利用多处理。
内核级线程
操作系统托管线程作用于内核,内核是操作系统的核心。
在这种情况下,Kernel 执行线程管理。应用程序区域中没有线程管理代码。内核线程由操作系统直接支持。任何应用程序都可以编程为多线程。应用程序中的所有线程在单个进程中都受支持。
内核维护整个进程和进程中各个线程的上下文信息。Kernel 的调度是基于线程完成的。Kernel 在 Kernel 空间中执行线程创建、调度和管理。内核线程的创建和管理速度通常比用户线程慢。内核级线程的示例包括 Windows、Solaris。
内核级线程的优点
以下是内核级线程的不同优点 -
- 内核可以同时将来自同一进程的多个线程调度到多个进程上。
- 如果一个进程中的一个线程被阻塞,则 Kernel 可以调度同一进程的另一个线程。
- 内核例程本身可以是多线程的。
内核级线程的缺点
- 内核线程的创建和管理速度通常比用户线程慢。
- 在同一进程中将控制权从一个线程转移到另一个线程需要切换到内核。
线程控制块 - TCB
线程控制块 (TCB) 可以定义为操作系统内核中主要包含线程信息的数据结构。存储在 TCB 中的特定于线程的信息将突出显示有关每个进程的一些重要信息。
请考虑与 TCB 中包含的线程相关的以下几点 -
- 线程标识 − 它是分配给每个新线程的唯一线程 ID (tid)。
- 线程状态 - 它包含与线程的状态(正在运行、可运行、非运行、死)相关的信息。
- 程序计数器 (PC) − 它指向线程的当前程序指令。
- Register set - 它包含分配给它们的线程的 register 值以进行计算。
- 堆栈指针 − 它指向进程中线程的堆栈。它包含 thread 作用域下的局部变量。
- Pointer to PCB − 它包含指向创建该线程的进程的指针。
进程与线程之间的关系
在多线程中,进程和线程是两个非常密切相关的术语,具有相同的目标,即使计算机能够同时做多件事。进程可以包含一个或多个线程,但相反,线程不能包含进程。但是,它们仍然是两个基本执行单位。程序执行一系列指令,同时启动进程和线程。
下表显示了进程和线程之间的比较 -
过程 | 线程 |
---|---|
流程是繁重的或资源密集型的 | 线程是轻量级的,它占用的资源比进程少。 |
进程切换需要与操作系统交互。 | 线程切换不需要与操作系统交互。 |
在多个处理环境中,每个进程执行相同的代码,但有自己的内存和文件资源。 | 所有线程都可以共享同一组打开的文件,即子进程。 |
如果一个进程被阻止,则在第一个进程被解除阻止之前,其他进程都无法执行。 | 当一个线程被阻塞并等待时,同一任务中的第二个线程可以运行。 |
不使用线程的多个进程会使用更多资源。 | 多线程进程使用的资源较少。 |
在多个进程中,每个进程都独立于其他进程运行。 | 一个线程可以读取、写入或更改另一个线程的数据。 |
如果父进程中有任何更改,则不会影响子进程。 | 如果主线程有任何变化,则可能会影响该进程的其他线程的行为。 |
若要与同级进程通信,进程必须使用进程间通信。 | 线程可以直接与该进程的其他线程通信。 |
多线程的概念
正如我们之前所讨论的,多线程是 CPU 通过并发执行多个线程来管理操作系统使用的能力。多线程的主要思想是通过将一个进程划分为多个线程来实现并行性。用更简单的方式来说,我们可以说多线程是通过使用线程的概念实现多任务处理的方式。
借助以下示例可以理解多线程的概念。
例假设我们正在运行一个进程。该过程可能是打开 MS Word 来编写某些内容。在此过程中,将分配一个线程来打开 MS word,另一个线程将需要写入。现在,假设如果我们想要编辑某些内容,则需要另一个线程来执行编辑任务,依此类推。
下图帮助我们了解内存中如何存在多个线程 -
在上图中,我们可以看到,一个进程中可以存在多个线程,其中每个线程都包含自己的寄存器集和局部变量。除此之外,进程中的所有线程都共享全局变量。
多线程的优点
现在让我们看看多线程的一些优点。优点如下 -
- 通信速度 − 多线程提高了计算速度,因为每个内核或处理器同时处理单独的线程。
- 程序保持响应 − 它允许程序保持响应,因为一个线程等待输入,而另一个线程同时运行 GUI。
- 访问全局变量 − 在多线程中,特定进程的所有线程都可以访问全局变量,如果全局变量有任何变化,那么其他线程也可以看到它。
- 资源利用率 − 在每个程序中运行多个线程可以更好地利用 CPU,并且 CPU 的空闲时间变得更短。
- 数据共享 − 不需要为每个线程提供额外的空间,因为程序中的线程可以共享相同的数据。
多线程的缺点
现在让我们看看多线程的一些缺点。缺点如下 -
- 不适合单处理器系统 - 与多处理器系统上的性能相比,多线程发现在单处理器系统上难以实现计算速度方面的性能。
- 安全问题 − 众所周知,程序中的所有线程共享相同的数据,因此始终存在安全问题,因为任何未知线程都可以更改数据。
- 复杂性增加 − 多线程处理会增加程序的复杂性,并且调试变得困难。
- 导致死锁状态 - 多线程处理可能导致程序面临达到死锁状态的潜在风险。
- 需要同步 − 需要同步以避免互斥。这会导致更多的内存和 CPU 利用率。