📜  Python中的多线程 |设置 1

📅  最后修改于: 2022-05-13 01:54:31.525000             🧑  作者: Mango

Python中的多线程 |设置 1

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

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

线

在计算中,进程是正在执行的计算机程序的一个实例。任何流程都有 3 个基本组成部分:

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

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

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

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

  • 线程标识符:为每个新线程分配唯一 id (TID)
  • 堆栈指针:指向进程中线程的堆栈。堆栈包含线程范围内的局部变量。
  • 程序计数器:存放线程当前正在执行的指令地址的寄存器。
  • 线程状态:可以是running、ready、waiting、start或done。
  • 线程的寄存器集:分配给线程进行计算的寄存器。
  • 父进程指针:指向线程所在进程的进程控制块 (PCB) 的指针。

考虑下图来理解进程和它的线程之间的关系:

多线程

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

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

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

多线程被定义为处理器同时执行多个线程的能力。

考虑下图,其中一个进程包含两个活动线程:

Python中的多线程

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

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

# Python program to illustrate the concept
# of threading
# importing the threading module
import threading
  
def print_cube(num):
    """
    function to print cube of given num
    """
    print("Cube: {}".format(num * num * num))
  
def print_square(num):
    """
    function to print square of given num
    """
    print("Square: {}".format(num * num))
  
if __name__ == "__main__":
    # creating thread
    t1 = threading.Thread(target=print_square, args=(10,))
    t2 = threading.Thread(target=print_cube, args=(10,))
  
    # starting thread 1
    t1.start()
    # starting thread 2
    t2.start()
  
    # wait until thread 1 is completely executed
    t1.join()
    # wait until thread 2 is completely executed
    t2.join()
  
    # both threads completely executed
    print("Done!")
Square: 100
Cube: 1000
Done!

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

  • 要导入线程模块,我们这样做:
    import threading
    
  • 要创建一个新线程,我们创建一个Thread类的对象。它需要以下参数:
    • target : 线程要执行的函数
    • args :要传递给目标函数的参数

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

    t1 = threading.Thread(target=print_square, args=(10,))
    t2 = threading.Thread(target=print_cube, args=(10,))
    
  • 要启动一个线程,我们使用Thread类的start方法。
    t1.start()
    t2.start()
    
  • 一旦线程启动,当前程序(你可以把它想象成一个主线程)也会继续执行。为了在线程完成之前停止当前程序的执行,我们使用join方法。
    t1.join()
    t2.join()
    

    结果,当前程序将首先等待t1的完成,然后t2 。一旦它们完成,则执行当前程序的剩余语句。

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

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

# Python program to illustrate the concept
# of threading
import threading
import os
  
def task1():
    print("Task 1 assigned to thread: {}".format(threading.current_thread().name))
    print("ID of process running task 1: {}".format(os.getpid()))
  
def task2():
    print("Task 2 assigned to thread: {}".format(threading.current_thread().name))
    print("ID of process running task 2: {}".format(os.getpid()))
  
if __name__ == "__main__":
  
    # print ID of current process
    print("ID of process running main program: {}".format(os.getpid()))
  
    # print name of main thread
    print("Main thread name: {}".format(threading.current_thread().name))
  
    # creating threads
    t1 = threading.Thread(target=task1, name='t1')
    t2 = threading.Thread(target=task2, name='t2')  
  
    # starting threads
    t1.start()
    t2.start()
  
    # wait until all threads finish
    t1.join()
    t2.join()
ID of process running main program: 11758
Main thread name: MainThread
Task 1 assigned to thread: t1
ID of process running task 1: 11758
Task 2 assigned to thread: t2
ID of process running task 2: 11758

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

  • 我们使用os.getpid()函数来获取当前进程的 ID。
    print("ID of process running main program: {}".format(os.getpid()))
    

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

  • 我们使用threading.main_thread()函数来获取主线程对象。在正常情况下,主线程是启动Python解释器的线程。线程对象的name属性用于获取线程的名称。
    print("Main thread name: {}".format(threading.main_thread().name))
    
  • 我们使用threading.current_thread()函数来获取当前线程对象。
    print("Task 1 assigned to thread: {}".format(threading.current_thread().name))
    

下面给出的图表清除了上述概念:

因此,这是对Python中的多线程的简要介绍。本系列的下一篇文章将介绍多线程之间的同步

Python中的多线程 |第 2 组(同步)