• Python线程


    什么是并行性(parallelism)

    早期的机器在 CPU 中只有一个内核(core),所有处理都在这个内核中进行。
    为什么内核的数量很重要——这是因为它说明了机器处理多种事情的能力。 如果您有 16 个内核,那么您可以同时执行 16 种不同的操作
    假设您要执行 16 种不同的加法运算,并假设每个运算需要 1 秒。 在单核机中,这些操作必须一个一个地执行,也就是说16个加法运算在16秒内完成。 现在在一台 16 核的机器上,你可以将 16 个加法操作同时部署到每个核上,并在 1 秒内完成工作。 这称为并行性

    线程处理(threading)

    线程(thread)是一组需要执行的操作。 一个线程将部署在 CPU 中的一个内核中。
    注意: 1 个线程只能部署在 1 个内核中,不能转移/交换。
    让我们将两个线程部署到一个内核。
    注意 :一个内核一次只能做一件事。
    在这里插入图片描述

    现在我们可以按我们想要的方式处理这两个线程。
    首先,我们可以处理第一个线程的一半。
    在这里插入图片描述
    现在可以处理下一个线程的一半。
    在这里插入图片描述
    其余一半的线程可以以类似的方式处理。
    在这里插入图片描述
    这就是线程——这是我们如何在同一个 CPU 内核上运行不同的东西。 线程处理(threading)是关于我们如何处理内核中的线程

    注意:线程不涉及在多个内核上运行。 它是关于如何在同一个内核中对一组程序(线程)进行排序。

    为什么我们需要线程处理?

    有时,线程可能会挂起(hanging),这意味着它应该在那个时间点处于空闲(idle)状态。 最好的例子是 time.sleep() 函数,它什么都不做,只是等待给定的时间。 当一个线程空闲/挂起时,我们可以继续处理另一个线程直到前一个线程变为活动状态当一个线程正在等待时,您可以同时处理另一个线程。
    这就是我们所说的并发计算(concurrent computing)。

    一个小例子

    让我们用一个小例子来解释线程。查看下面的代码片段。

    #Part One of the code
    import time
    print(1)
    time.sleep(10)
    print('Done sleeping)
    print(2)
    
    #Part Two of the code
    print(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出如下所示:

    1
    Done sleeping
    2
    3
    
    • 1
    • 2
    • 3
    • 4

    现在让我们假设您将代码作为两个线程执行。 第一部分作为一个线程,第二部分作为一个线程。 (注意——默认情况下,Python 代码没有配置线程——我们需要导入threading 库来做到这一点。)

    首先导入库 threading,然后打印‘1’。 现在线程进入睡眠状态。 这就是线程发挥作用的地方。

    在这里插入图片描述
    内核现在切换到另一个线程。

    在这里插入图片描述
    现在打印了“3”。因为所有进程都是在线程2中完成的,所以内核现在切换回线程1(它仍然处于睡眠状态)。
    在这里插入图片描述
    现在,在睡眠时间之后,’ 2 '被打印出来。
    所以输出是

    1
    3
    Done sleeping
    2
    
    • 1
    • 2
    • 3
    • 4

    实际例子

    I/O进程(processes)受益于线程。
    假设你正在Netflix上看《肖申克的救赎》。当你看着Andy Dufresne在监狱里受苦时,会发生两件事:一,应用程序从服务器获取数据;二,获取的数据会像电影一样显示在你的屏幕上。
    在这里插入图片描述
    想象一下如果没有线程处理会是什么情况。你需要偶尔等待视频被下载,观看被获取的片段,等待下一个片段被下载,等等。
    由于有了线程处理,我们可以将两个进程分成不同的线程。当一个线程获取数据时(也就是说,它处于挂起/休眠模式),另一个线程可以向您展示Morgan Freeman的表演。
    它对作为数据科学家的您也非常有用。例如,当您从多个网页抓取数据时,您可以简单地将它们部署在多个线程中,使其更快。即使将数据推送到服务器,也可以在多个线程中进行,这样当一个线程空闲时,就可以触发其他线程。

    更细致的例子

    如前所述,默认情况下,Python代码不提供线程处理——我们需要导入 threading 库来实现这一点。

    import threading
    import time
    
    def sleepy_man(secs):
        print('Starting to sleep inside')
        time.sleep(secs)
        print('Woke up inside')
    
    x = threading.Thread(target = sleepy_man, args = (1,))
    x.start()
    print(threading.activeCount())
    time.sleep(1.2)
    print('Done')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    代码输出如下:

    Starting to sleep inside
    2
    Woke up inside
    Done
    
    • 1
    • 2
    • 3
    • 4

    首先,让我一步一步解释代码。 然后我们将分析输出。

    • 首先导入 threading 和 time 库。 threading 是允许我们创建线程的库,time 是包含函数 sleep 的库。
    • 函数 sleepy_man 接受一个参数——秒。 它首先打印“Starting to sleep inside”。 然后它会休眠几秒钟,然后打印“Woke up inside”。
    • 这是我们开始创建线程的部分。 我们需要通过调用类threading.Thread来定义。 我们需要传递两个参数——target 是需要线程化的函数块,args 是需要传递给函数的参数。 返回一个线程对象,该对象现在存储在 x 中。
    x = threading.Thread(target = sleepy_man, args = (1,))
    
    • 1
    • 现在定义线程类后,我们需要调用函数 start() 来启动线程
    x.start()
    
    • 1
    • 注意:现在我们有了两个线程。该程序的一个默认线程和一个我们定义的新线程因此活动线程数为 2
    • 因此,该语句应该输出’ 2 '。
    print(threading.activeCount())
    
    • 1

    现在让我们来看看控制的流程。一旦调用 start() 方法,它就会触发 sleepy_man(),并在单独的线程中运行
    主程序也将作为另一个线程并行运行。流程如下图所示。
    在这里插入图片描述现在让我们增加函数中程序休眠的时间

    import threading
    import time
    
    def sleepy_man(secs):
        print('Starting to sleep inside')
        time.sleep(secs)
        print('Woke up inside')
    
    x = threading.Thread(target = sleepy_man, args = (4,))
    x.start()
    print(threading.activeCount())
    time.sleep(1.2)
    print('Done')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    输出如下:

    Starting to sleep inside
    2
    Done
    Woke up inside
    
    • 1
    • 2
    • 3
    • 4

    流程如下图所示
    在这里插入图片描述
    现在让我们运行一个触发多个线程的 for 循环。

    import threading
    import time
    
    def sleepy_man(secs):
        print('Starting to sleep inside - Iteration {}'.format(5-secs))
        time.sleep(secs)
        print('Woke up inside - Iteration {}'.format(5-secs))
    
    for i in range(3):
        x = threading.Thread(target = sleepy_man, args = (5-i,))
        x.start()
    
    print('Active threads- ', threading.activeCount())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在每次迭代中,我们触发一个线程。注意,我们分别在第1次、第2次和第3次迭代时传递参数5、4、3。因此sleepy_man()的睡眠时间分别为5秒、4秒和3秒。
    输出如下:

    Starting to sleep inside - Iteration 0
    Starting to sleep inside - Iteration 1
    Starting to sleep inside - Iteration 2
    Active threads-  4
    Woke up inside - Iteration 2
    Woke up inside - Iteration 1
    Woke up inside - Iteration 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因此,我们已经看到了如何定义和触发多个线程,确保了更好的处理方式,这对于繁重的I/O操作非常重要。

    参考

    本文主要参考Beginners Guide to Threading in Python

  • 相关阅读:
    Springboot毕设项目基于Springboot的手机电商网站lmo47(java+VUE+Mybatis+Maven+Mysql)
    049-第三代软件开发-软件部署脚本(一)
    驱动开发--day2
    Application.OpenForms
    9月7日扒面经
    ST/意法STTH30ST06-Y车规FRD,原厂渠道ASEMI代理
    【云原生 | Kubernetes 系列】K8s 实战 一文学会如何从 PodSecurityPolicy 迁移到内置的 PodSecurity 准入控制器
    Codeforces Global Round 21(只会俩题)
    预防山体滑坡,泥石流监测智能预警系统
    设计模式:策略模式
  • 原文地址:https://blog.csdn.net/OrdinaryMatthew/article/details/125893237