Concurrency In Python 简明教程

Concurrency in Python - Threads

一般来说,众所周知,线是一种非常薄的扭曲字符串,通常由棉或丝绸制成,用于缝制衣服等。计算机编程领域也使用“线”这个术语。那么,如何将用于缝制衣服的线与用于计算机编程的线联系起来?这里两个线执行的角色是类似的。在衣服中,线将布料固定在一起,而在计算机编程中,线将计算机程序固定在一起,并允许程序按顺序执行或一次执行许多动作。

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

States of Thread

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

New Thread

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

Runnable

随着新创建的线程启动,线程变得可运行,即等待运行。在此状态下,它具有所有资源,但任务调度程序仍未将其计划运行。

Running

在此状态下,线程取得进展并执行任务,该任务已由任务调度程序选择运行。现在,线程可以转到死状态或不可运行/等待状态。

Non-running/waiting

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

Dead

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

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

dead

Types of Thread

在本节中,我们将看到不同类型的线程。下面对类型进行了描述 -

User Level Threads

这些是由用户管理的线程。

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

用户级线程的示例有 -

  1. Java threads

  2. POSIX threads

user level

Advantages of User level Threads

以下是用户级线程的不同优点 -

  1. 线程切换不需要内核模式权限。

  2. 用户级线程可以在任何操作系统上运行。

  3. 调度可以在用户级线程中特定于应用程序。

  4. 用户级线程创建和管理起来很快。

Disadvantages of User level Threads

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

  1. 在典型的操作系统中,大多数系统调用都是阻塞的。

  2. 多线程应用程序无法利用多进程。

Kernel Level Threads

操作系统管理的线程在内核上运行,内核是操作系统的核心。

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

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

kernal

Advantages of Kernel Level Threads

以下是在内核级线程中不同的优势:-

  1. 内核可以在多个进程上同时调度从同一进程中的多个线程。

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

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

Disadvantages of Kernel Level Threads

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

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

Thread Control Block - TCB

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

考虑与 TCB 中包含的线程有关的以下几点:-

  1. Thread identification − 它是分配给每个新线程的唯一线程 ID (tid)。

  2. Thread state − 它包含与线程状态(运行、可运行、不可运行、死亡)相关的信息。

  3. Program Counter (PC) − 它指向线程当前的程序指令。

  4. Register set − 它包含分配给线程用于计算的线程寄存器值。

  5. Stack Pointer − 它指向进程中线程的堆栈。它包含线程作用域下的局部变量。

  6. Pointer to PCB − 它包含指向创建该线程的进程的指针。

pcb

Relation between process & thread

在多线程中,进程和线程是两个非常密切相关的术语,它们的目标是使计算机能够一次执行多项操作。一个进程可以包含一个或多个线程,但相反,线程不能包含一个进程。然而,它们仍然是两个基本的执行单位。一个执行一系列指令的程序启动了进程和线程。

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

Process

Thread

进程是重量级或资源密集型的。

线程是轻量级的,比进程消耗的资源少。

进程切换需要与操作系统交互。

线程切换不需要与操作系统交互。

在多个处理环境中,每个进程执行相同的代码,但有自己的内存和文件资源。

所有线程都可以共享同一组打开的文件、子进程。

如果一个进程被阻塞,那么在第一个进程未被解锁之前,其他进程都不能执行。

当一个线程被阻塞并等待时,同一个任务中的另一个线程可以运行。

不使用线程的多个进程使用更多的资源。

多线程进程使用更少的资源。

在多个进程中,每个进程独立于其他进程运行。

一个线程可以读取、写入或更改另一个线程的数据。

如果父进程有任何更改,那么它不会影响子进程。

如果主线程有任何更改,那么它可能会影响该进程其他线程的行为。

要与同级进程通信,进程必须使用进程间通信。

线程可以直接与该进程的其他线程通信。

Concept of Multithreading

正如我们之前讨论的那样,多线程是 CPU 通过同时执行多个线程来管理操作系统使用情况的能力。多线程的主要思想是通过将一个进程分解为多个线程来实现并行性。用更简单的方式来说,我们可以说多线程是通过使用线程的概念来实现多任务的方式。

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

Example

假设我们正在运行一个进程。该进程可能是为了打开 MS Word 以便书写一些内容。在此类进程中,将分配一个线程打开 MS Word,而另一个线程将需要进行书写。现在,假设如果我们想编辑一些内容,那么将需要另一个线程执行编辑任务,依此类推。

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

multithreading

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

Pros of Multithreading

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

  1. Speed of communication – 多线程提高了计算速度,这是因为每个内核或处理器同时处理单独的线程。

  2. Program remains responsive – 它允许程序保持响应,这是因为一个线程等待输入而另一个同时运行 GUI。

  3. Access to global variables – 在多线程中,特定进程的所有线程都可以访问全局变量,如果全局变量有任何更改,那么其他线程也可以看到。

  4. Utilization of resources – 在每个程序中运行多个线程可以更好地利用 CPU,并且 CPU 的空闲时间也会减少。

  5. Sharing of data – 由于程序中的线程可以共享相同的数据,因此不需要为每个线程分配额外的空间。

Cons of Multithreading

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

  1. Not suitable for single processor system – 与多处理器系统上的性能相比,多线程很难在单处理器系统上实现计算速度方面的性能。

  2. Issue of security – 正如我们所知道的,程序中的所有线程共享相同的数据,因此始终存在安全问题,因为任何未知线程都可以更改数据。

  3. Increase in complexity – 多线程会增加程序的复杂性,并且调试变得困难。

  4. Lead to deadlock state – 多线程可能导致程序达到死锁状态的潜在风险。

  5. Synchronization required – 避免相互排斥需要同步。这会导致更多的内存和 CPU 利用率。