• 多线程和线程池


    多线程和线程池

    1.基本理论
    1)进程和线程

    进程: 一个正在运行的应用程序就是一个进程,每个进程均运行在其专门且受保护的内存空间中

    线程: 线程是进程执行任务的基本单元(一个进程中的任务都是在线程中执行的)

    进程就是车间,线程就是车间里面的工人。
    一个进程中默认有一个线程,这个线程叫主线程

    2)线程的特点

    如果在一个线程中执行多个任务,任务是串行执行的。
    (当一个程序中有很多个任务的时候,如果只有一个线程,那么程序的执行效率会很低)

    3)多线程

    一个进程中有多个线程就是多线程
    多线程执行任务的时候,多个任务可以同时(并行)执行

    4)多线程原理

    一个CPU同一时间只能调度一个线程,多线程其实是CPU快速的在多个线程之间切换,造成多个线程同时执行的假象
    (提高CPU的利用率来提供程序执行效率)

    2.Python使用多线程的方法

    一个进程默认只有一个线程,这个线程叫主线程。主线程以外的线程都叫子线程。

    python程序中如果需要子线程,必须创建线程类(Thread)的对象

    from threading import Thread
    
    • 1

    线程对象 = Thread(target=函数,args=元组)
    a.函数 - 可以是普通函数函数名,也可以是匿名函数。这个函数就是需要在子线程中执行的1任务。
    b.元组 - 元组中的元素就是子线程中调用target对应的函数的时候需要的参数

    from time import sleep
    def download(name):
        print('开始下载')
        sleep(2)
        print('下载完毕')
    
    # 1)创建线程对象
    t1 = Thread(target=download, args=('肖生客的救赎',))
    t2 = Thread(target=download, args=('霸王别姬',))
    t3 = Thread(target=download, args=('阿甘正传',))
    
    
    # 2)启动线程  - 让子线程调用对应的函数
    # 线程对象.start()
    t1.start()
    t2.start()
    t3.start()
    print('全部完成')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    基本同时完成

    3.线程的等待和阻塞

    上诉的逻辑中print的逻辑很明显是自上而下的,但是每个线程刚开始的时候,print就会开始执行了,导致。电影每下载完成就已经打印了print。跟我们认识的下载完成后打印不一样,因为主线程不是妨碍多线程的任务,这个时候需要让所有线程的任务全部执行完毕后才打印,就需要线程的阻塞。

    语法: 线程对象.join
    from threading import Thread
    from time import sleep
    from datetime import datetime
    from random import randint
    
    
    def download(name):
        print(f'{name}开始下载:{datetime.now()}')
        sleep(randint(2, 7))
        print(f'{name}下载结束:{datetime.now()}')
    
    
    if __name__ == '__main__':
        # 示例1:三个电影都下载结束后打印'全部下载完成'
        t1 = Thread(target=download, args=('明日战机'))
        t2 = Thread(target=download, args=('斗罗大陆'))
        t3 = Thread(target=download, args=('独行月球'))
    
        t1.start()
        t2.start()
        t3.start()
    
        # 示例1
        # 1.子线程对象.join()    -   阻塞当前线程直到指定子线程任务完成
        t1.join()
        t2.join()
        t3.join()
        print('全部完成')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    4:创建线程池
    1. 线程池 - 管理多个线程的工具
    线程池工作原理:先创建指定个数的线程,然后添加多个任务(任务数量>线程数量),
    让线程池中的线程去执行添加的所有任务,直到所有任务都执行完(线程池中的每个线程可能会执行多个任务)
    from concurrent.futures import ThreadPoolExecutor
    
    • 1

    使用线程池需要导入的模块

    1)创建线程池对象

    ThreadPoolExecutor(线程数最大值)

    pool = ThreadPoolExecutor(3)
    
    • 1
    2)添加任务
    def download(name):
        print(f'{name}开始下载:{datetime.now()}', current_thread())
        sleep(randint(2, 7))
        print(f'{name}下载结束:{datetime.now()}')
    
    • 1
    • 2
    • 3
    • 4
    补充:current_thread(),查看当前线程ID

    添加任务的方式有两种

    a.一次添加一个任务: submit(函数, 实参1, 实参2, 实参3,…)

    注意:实参的数量由前面的函数在调用的时候需要的实参来决定
    pool.submit(download, '肖生克的救赎')
    pool.submit(download, '霸王别姬')
    
    • 1
    • 2

    b.同时添加多个任务: map(函数, 参数对应的序列)

    注意:使用map添加多个任务的时候,任务对应的函数必须是有且只有一个参数的函数
    pool.map(download, ['V字仇杀队', '恐怖游轮', '沉默的羔羊'])
    
    • 1
    3.关闭线程池

    线程池关闭后无法再添加新的任务,并且会阻塞当前线程等待整个线程池的任务都完成

    语法:线程池对象.shutdown()
    pool.shutdown()
    
    • 1
  • 相关阅读:
    要把项目问题管理好,项目经理需要这8个步骤!
    五、stm32-SysTick(系统定时器)
    架构师系列-Nginx、OpenResty(三)- 负载均衡配置
    数据结构与算法(C语言版)P6---队列
    JavaScript 框架之战结束:React 是最终赢家?
    8.StringTable(字符串常量池)
    数据库分区是什么?
    hbase manager 2.0.9 安装
    Kubernetes技术与架构(八)
    羽夏壳世界——异或加密的实现
  • 原文地址:https://blog.csdn.net/ZiXiaoAo/article/details/126450299