• 多线程


    多线程

    进程和线程

    进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。

    进程

    本质上就是一段程序的运行过程(抽象概念)

    最小的资源单位(操作系统分配cpu,内存资源的基本单位)

    线程

    最小的执行单元(实例),是cpu调度和分派的基本单位

    每个线程都有自己的堆栈和局部变量

    线程在同一进程中的各个线程,都可以共享该进程所拥有的资源

    1.一个程序至少有一个进程,一个进程至少有一个线程。(进程可以理解为线程的容器),一个进程里可以开辟多个线程和进程

    2.进程在执行过程中拥有独立的内存单元,而多个线程共享这个进程的内存,从而极大地提高了程序的运行效率

    3.一个线程(主线程创建子线程)可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行

    同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的进程id,这意味着,线程可以访问该进程的每一个内存资源;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。

    并发&并行

    并发:系统具有处理多个任务的能力,cpu疯狂切换(单核)

    并行:系统具备同时处理多个任务的能力(多核)

    同步&异步

    同步:我煮饭,我等煮好饭去炒菜--等

    异步:我煮饭的过程中,可以去炒菜--不等

    python解释器的GIL锁

    GIL解决什么问题?

    Python使用引用计数来管理内存,x=1,如果线程执行到1,这个时候垃圾回收线程来执行,会发现x引用计数为0,就会把x给干掉,显然,这样是不对的。

    无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行

    一个python进程同一时间只有一个线程能被cpu调用(多核对它基本没有用)

    但是可以开启多个进程,然后每个进程就可以各有一个线程丢给一个cpu,来实现并行

    线程抢占的就是GIL锁

    计算密集型:多进程效率高

    I/O密集型:多线程效率高(IO过程中cpu会有空闲时间,可以利用空闲时间做别的任务)

    多线程或者(多进程+携程)用于IO密集型,如socket,爬虫,web

    多进程用于计算密集型,如金融分析(但是不推荐)

    python中的多线程

    例1

    如下有三个线程,一个主线程,主线程开辟了两个子线程

    主线程最先运行完毕,t1子线程运行了3秒,t2子线程运行了6秒

    整个进程花费了6秒多一点结束

    import threading
    import time
    
    def zx(t,s):
        time.sleep(s)
        print(t)
    
    
    if __name__ == '__main__':
        t1=threading.Thread(target=zx,kwargs={"t":"t1","s":3})
        t1.start()
    
        t1=threading.Thread(target=zx,kwargs={"t":"t2","s":6})
        t1.start()
    
        print("main")
    

    main
    t1
    t2

    Process finished with exit code 0
    例2

    和上面一样的知识点

    import time
    import threading
    
    def music():
        print("开始听歌")
        time.sleep(3)
        print("停止听歌")
    
    def game():
        print("开始玩游戏")
        time.sleep(6)
        print("停止玩游戏")
    
    if __name__ == '__main__':
        t1=threading.Thread(target=music)
        t2=threading.Thread(target=game)
        t1.start()
        t2.start()
    
        print("main")
    
    

    开始听歌
    开始玩游戏
    main
    停止听歌
    停止玩游戏

    Process finished with exit code 0

    常用方法和属性

    threading模块提供的一些方法:
    # threading.currentThread(): 返回当前的线程对象。
    # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
    
    线程对象方法
    #ident:线程的id
    # run():  线程被cpu调度后自动执行线程对象的run方法
    # start():启动线程活动。
    # isAlive(): 返回线程是否活动的。
    # getName(): 返回线程名。
    # setName(): 设置线程名。
    

    join() 线程等待

    join():在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

    看懂下面代码者,方可大成

    join()相当于,执行完这个子线程,再去执行主线程下面的代码

    import time
    import threading
    
    def music():
        print("开始听歌")
        time.sleep(3)
        print("停止听歌")
    
    def game():
        print("开始玩游戏")
        time.sleep(6)
        print("停止玩游戏")
    
    if __name__ == '__main__':
        t1=threading.Thread(target=music)
        t2=threading.Thread(target=game)
        t1.start()
    
        t1.join()
    
        t2.start()
    
        t2.join()
    
        print("main")
    
    

    开始听歌
    停止听歌
    开始玩游戏
    停止玩游戏
    main

    Process finished with exit code 0

    setDaemon()守护线程

    setDaemon(True):

    将线程声明为守护线程,必须在start() 方法调用之前设置,当我们 在程序运行中,执行一个主线程,主线程运行完毕,想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 setDaemon方法

    例1

    当主线程运行完毕,去检验t1和t2,发现他们都是守护线程,直接退出

    import time
    import threading
    
    def music():
        print("开始听歌")
        time.sleep(3)
        print("停止听歌")
    
    def game():
        print("开始玩游戏")
        time.sleep(6)
        print("停止玩游戏")
    
    if __name__ == '__main__':
        t1=threading.Thread(target=music)
        t2=threading.Thread(target=game)
        t1.setDaemon(True)
        t2.setDaemon(True)
        t1.start()
        t2.start()
        print("main")
    

    开始听歌
    开始玩游戏
    main

    Process finished with exit code 0

    例2

    当主线程运行完毕,去检验t1和t2,发现t1不是守护线程,t2是守护线程,t1耗时3秒,t1执行完毕,直接退出,因为t2耗时6秒,还是守护线程,主线程不用管它

    import time
    import threading
    
    def music():
        print("开始听歌")
        time.sleep(3)
        print("停止听歌")
    
    def game():
        print("开始玩游戏")
        time.sleep(6)
        print("停止玩游戏")
    
    if __name__ == '__main__':
        t1=threading.Thread(target=music)
        t2=threading.Thread(target=game)
        t2.setDaemon(True)
        t1.start()
        t2.start()
        print("main")
    

    开始听歌
    开始玩游戏
    main
    停止听歌

    Process finished with exit code 0

    定时器

    线程延迟执行

    from threading import Thread,Timer
    import time
    
    def task():
        print('线程执行了')
        time.sleep(2)
        print('线程结束了')
    
    t = Timer(4,task) # 过了4s后开启了一个线程
    t.start()
    print("end")
    
    end
    线程执行了
    线程结束了
    
    
  • 相关阅读:
    说说我当初是如何学Linux的
    案例八:shell自动化管理账本脚本
    案例七:shell实现开机自动播放挂载本地yum仓库程序
    案例六:shell脚本监控httpd服务80端口状态
    案例五:shell脚本实现定时监控http服务的运行状态
    案例四:Shell脚本生成随机密码
    案例三:shell统计ip访问情况并分析访问日志
    案例二:shell脚本获取当前日期和时间及磁盘使情况
    案例一:shell脚本指定日期减去一天
    Linux:保证数据安全落盘
  • 原文地址:https://www.cnblogs.com/zx125/p/11440563.html
Copyright © 2020-2023  润新知