什么是Python多线程,如何实现的?

2023年 12月 11日 16.1k 0

什么是多线程

多线程是在单个进程中实现并行性的一种方法,能够执行同时进行的任务。

在单个进程内可以创建多个线程,并在该进程内并行执行较小的任务。

单个进程中的线程共享一个公共内存空间,但它们的堆栈跟踪和寄存器是独立的。

由于共享内存,它们的计算成本较低。

图片[1]-什么是Python多线程,如何实现的?-不念博客

Python中的多线程主要用于执行I/O操作,即如果程序的某个部分正在执行I/O操作,则其余程序可以保持响应。

然而,在Python的实现中,由于全局解释器锁(GIL)的存在,多线程无法实现真正的并行性。

简而言之,GIL是一个互斥锁,一次只允许一个线程与Python字节码交互,即使在多线程模式下,一次也只能有一个线程执行字节码。

这样做是为了在CPython中保持线程安全,但它限制了多线程的性能优势。

多线程实现

现在,我们使用Python实现一个基本的多线程示例。

Python有一个内置的threading模块用于多线程实现。

1、导入库:

import threading
import os

2、计算平方的函数:

这是一个用于计算数字平方的简单函数,它接受一个数字列表作为输入,并输出列表中每个数字的平方,同时输出使用的线程名称和与该线程关联的进程ID。

def calculate_squares(numbers):
    for num in numbers:
        square = num * num
        print(
            f"Square of the number {num} is {square} | Thread Name {threading.current_thread().name} | PID of the process {os.getpid()}"
        )

3、主函数:

本示例有一个数字列表,将其平均分成两半,并分别命名为first_halfsecond_half。现在,将为这些列表分配两个独立的线程t1t2

Thread函数创建一个新线程,该线程接受一个带有参数列表的函数作为输入。还可以为线程分配一个单独的名称。

.start()函数将开始执行这些线程,而.join()函数将阻塞主线程的执行,直到给定的线程完全执行完毕。

if __name__ == "__main__":
    numbers = [1, 2, 3, 4, 5, 6, 7, 8]
    half = len(numbers) // 2
    first_half = numbers[:half]
    second_half = numbers[half:]

    t1 = threading.Thread(target=calculate_squares, name="t1", args=(first_half,))
    t2 = threading.Thread(target=calculate_squares, name="t2", args=(second_half,))

    t1.start()
    t2.start()

    t1.join()
    t2.join()

输出:

Square of the number 1 is 1 | Thread Name t1 | PID of the process 345
Square of the number 2 is 4 | Thread Name t1 | PID of the process 345
Square of the number 5 is 25 | Thread Name t2 | PID of the process 345
Square of the number 3 is 9 | Thread Name t1 | PID of the process 345
Square of the number 6 is 36 | Thread Name t2 | PID of the process 345
Square of the number 4 is 16 | Thread Name t1 | PID of the process 345
Square of the number 7 is 49 | Thread Name t2 | PID of the process 345
Square of the number 8 is 64 | Thread Name t2 | PID of the process 345

注意:上述创建的所有线程都是非守护线程。要创建守护线程,需要编写t1.setDaemon(True),将线程t1设置为守护线程。

现在来了解一下上述代码生成的输出结果。可以观察到两个线程的进程ID(即PID)保持不变,这意味着这两个线程属于同一个进程。

还可以观察到输出并非按顺序生成。第一行中可以看到是线程1生成的输出,然后在第三行是线程2生成的输出,接着在第四行,再次是线程1生成的输出。这清楚地表明这些线程是同时工作的。

并发并不意味着这两个线程并行执行,因为一次只有一个线程被执行。它不会减少执行时间,与顺序执行所需的时间相同。CPU开始执行一个线程,但在中途离开,并切换到另一个线程,过一段时间后,又回到主线程,并从上次离开的地方开始执行。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论