python 多线程篇

文章目录

  • 线程
  • 多线程

本文将会介绍 Python 编程语言中多线程处理的基础知识。就像多处理一样,多线程是实现多任务处理的一种方式。在多线程处理中,使用 线程的概念。

让我们首先了解计算机体系结构中线程的概念。

线程

在计算中,进程是正在执行的计算机程序的实例。任何过程都有 3 个基本组件:

  • 可执行程序。
  • 程序所需的关联数据(变量、工作空间、缓冲区等)
  • 程序的执行上下文(进程状态)

线程是进程中可以安排执行的实体。此外,它是可以在操作系统(操作系统)中执行的最小处理单元。

简单来说,线程是程序中可以独立于其他代码执行的此类指令序列。为简单起见,您可以假设线程只是进程的子集!

线程在线程控制块 (TCB) 中包含所有这些信息:

  • 线程标识符: 将唯一 ID (TID) 分配给每个新线程
  • 堆栈指针: 指向进程中的线程堆栈。堆栈包含线程作用域下的局部变量。
  • 程序计数器: 存储线程当前正在执行的指令地址的寄存器。
  • 线程状态: 可以是正在运行、就绪、等待、启动或完成。
  • 线程的寄存器集: 分配给线程进行计算的寄存器。
  • 父进程指针: 指向线程所在的进程的过程控制块 (PCB) 的指针。

请参考下图以了解进程与其线程之间的关系:

python 多线程篇_第1张图片

多线程

一个进程中可以存在多个线程,其中:

  • 每个线程都包含自己的寄存器集局部变量(存储在堆栈中)。
  • 进程的所有线程共享全局变量(存储在堆中)程序代码

请参考下图以了解内存中如何存在多个线程:

python 多线程篇_第2张图片

在Python中,线程模块提供了一个非常简单直观的API,用于在程序中生成多个线程。

让我们考虑一个使用线程模块的简单示例:

import threading


def print_cube(num):
    """用于打印给定数字的多维数据集的函数"""
    print("Cube: {}".format(num * num * num))


def print_square(num):
    """函数打印给定数值的平方"""
    print("Square: {}".format(num * num))


if __name__ == "__main__":
    # 创建线程
    t1 = threading.Thread(target=print_square, args=(10,))
    t2 = threading.Thread(target=print_cube, args=(10,))

    # 启动线程1
    t1.start()
    # 启动线程2
    t2.start()

    # 等待线程1完全执行
    t1.join()
    # 等待线程2完全执行
    t2.join()

    # 两个线程都已完全执行
    print("Done!")

运行结果:

python 多线程篇_第3张图片

让我们试着理解上面的代码:

  • 要导入线程模块,我们需要:

    import threading
    
  • 要创建一个新线程,我们创建一个 Thread 类的对象。它需要以下参数:

    • 目标:线程要执行的函数
    • args:要传递给目标函数的参数

    在上面的例子中,我们创建了2个具有不同目标函数的线程:

    t1 = threading.Thread(target=print_square, args=(10,))
    t2 = threading.Thread(target=print_cube, args=(10,))
    
  • 要启动线程,我们使用 Thread 类的 start 方法。

    t1.start()
    t2.start()
    
  • 一旦线程启动,当前程序(你可以把它想象成一个主线程)也会继续执行。为了停止当前程序的执行,直到线程完成,我们使用连接方法。

    t1.join()
    t2.join()
    

    因此,当前程序将首先等待 t1 的完成,然后等待 t2 完成。完成后,将执行当前程序的其余语句。

考虑下图,以更好地了解上述程序的工作原理:

python 多线程篇_第4张图片

考虑下面给出的python程序,其中我们为每个任务打印线程名称和相应的进程:

import threading
import os


def task1():
    print("任务1分配给线程: {}".format(threading.current_thread().name))
    print("运行任务1的进程ID: {}".format(os.getpid()))


def task2():
    print("任务2分配给线程: {}".format(threading.current_thread().name))
    print("运行任务2的进程ID: {}".format(os.getpid()))


if __name__ == "__main__":
    # 打印当前进程的ID
    print("运行主程序的进程ID: {}".format(os.getpid()))

    # 打印主线程名称
    print("主线程名称: {}".format(threading.current_thread().name))

    # 创建线程
    t1 = threading.Thread(target=task1, name='t1')
    t2 = threading.Thread(target=task2, name='t2')

    # 启动线程
    t1.start()
    t2.start()

    # 等待所有线程完成
    t1.join()
    t2.join()

运行结果:

python 多线程篇_第5张图片

让我们试着理解上面的代码:

  • 我们使用 os.getpid() 函数来获取当前进程的 ID。

    print("运行主程序的进程ID: {}".format(os.getpid()))
    

    从输出中可以清楚地看出,所有线程的进程 ID 都保持不变。

  • 我们使用threading.main_thread() 函数来获取主线程对象。在正常情况下,主线程是启动Python解释器的线程。线程对象的 name 属性用于获取线程的名称。

    print("主线程名称: {}".format(threading.main_thread().name))
    
  • 我们使用 threading.current_thread() 函数来获取当前线程对象。

    print("任务1分配的线程: {}".format(threading.current_thread().name))
    

下图阐明了上述概念:

python 多线程篇_第6张图片

你可能感兴趣的:(python,python,开发语言)