美文网首页
2018-08-04(15.5)多线程

2018-08-04(15.5)多线程

作者: 棕色试剂瓶 | 来源:发表于2018-08-04 10:13 被阅读0次

    python基础语法(15.5)

    多线程

    初步了解多线程

    (个人理解)电脑的cpu一般情况下一次只能给一个进程提供服务,它给每个进程提供服务的时间是相同的,到达时间后就会给下一个进程提供服务,这种行为被称之为时间片轮转。但是由于cpu的速度实在太快了,所以造成看似好像是所有程序一起并发执行。

    但是有些时候,有些程序较为耗费资源,一般cpu轮转提供给它的服务不足以支撑它运行。这时候他就会开多天线程,cpu会轮转给每个线程提供单位时间的服务。如此一来就可以让该程序获得更多的资源。

    线程是应用程序中工作的最小单位。Python当前的多线程库没有实现优先级,线程组,线程也不能被停止,暂停,恢复,中断。

    多线程具有以下有点:

    • 使用线程可以把程序中长时间占用资源的任务放到后台处理。
    • 可以让显示界面更加灵活,通过点击等事件去触发一些线程,并且可以在线程进行的过程中给用户相应的反馈。
    • 提升程序运行速度。
    • 一些不需要连续使用系统资源的任务,系统可以在任务间歇将CPU分配给其它进程,更好的利用系统资源。

    如何使用多线程

    Python的标准库给我们提供了两个标准模块:_thread 和threading。

    _thread是低级模块,threading是高级模块,它对 _thread 进行了封装,我们常用threading模块。

    threading提供的类

    Thread

    该类可以按一下两种方式安全的进行子类化:

    1. 通过将可调用对象传递给构造函数。
    2. 通过重写子类中的run()方法。

    这是一个构造函数,调用它需要传入关键字参数,其中

    ​ *group默认为空,为ThreadGroup将来扩展保留的。

    ​ *target是run()调用的可调用的对象方法。默认为none,表示不调用任何内容。

    ​ *name是线程名称,默认情况下,构造函数的唯一名称,形式为“Thread-N”,其中N是小十进制数。

    ​ *args是目标调用的参数元组,默认为()

    ​ *kwargs是目标关键字参数的字典调用,默认为{}

    ​ 如果子类重写构造函数,则必须确保调用积累构造函数(Thread_init_())

    Lock

    Rlock

    Condition

    Event

    Timer

    local

    [Bounded]Semaphore

    实例方法

    • isAlive():返回线程是否在运行,在启动后,终止前都称之为运行。

    • get/setName(name):获取/设置线程名

    • start()“线程准备就绪,等待CPU调度

    • join([timeout]):阻塞当前的上下文环境的线程,直到调用此方法的线程终止或达到指定的timeout(可选参数)

      • 上下文

      每个线程都有属于它的一组CPU寄存器,称之为线程的上下文,上下文反应了线程上次运行该线程的CPU寄存器状态。

      指令指针和堆栈指针寄存器是线程上下文中两个重要的寄存器,线程总是在进程得到的上下文中运行的,这些地址都用于标注拥有线程的进程地址空间中的内存。

    threading模块提供的常量

    在threading.TIMEOUT_MAX设置threading全局超时时间。

    以函数的形式来开启线程

    import threading 
    import time
    #将要执行的方法作为参数传递给Thread的构造方法
    def action(arg):
        time.sleep(1)
        print(threading.current_thread()) # 返回当前的线程对象
        
        print("The arg is:{0}".format(arg))#注意是format不是formate
    
    for i in range(4):
        t = threading.Thread(target = action,args = (i,)) # 创建调用action的线程
        t.start() # 就绪线程,会自动执行run()来运行线程
        
    if __name__ == "__main__":
        print(threading.current_thread())
        print("main thread End")
    

    运行结果:

    <_MainThread(MainThread, started 24928)>
    main thread End
    <Thread(Thread-1, started 15260)>
    The arg is :0
    <Thread(Thread-2, started 18576)>
    <Thread(Thread-3, started 19916)>
    The arg is :2
    The arg is :1
    <Thread(Thread-4, started 296)>
    The arg is :3

    用类来包装线程对象

    即自己定义一个类来继承Thread,通过重写run()方法来开启多线程。

    代码实例:

    class MyThread(threading.Thread):
        def __init__(self,arg):
            super(MyThread,self).__init__() #调用父类
            self.arg = arg #初始化传入参数
        def run(self): #重写该方法,定义每个线程要运行的函数
            time.sleep(1)
            print("The arg is :{0}".format(self.arg))
    for i in range(4):
        t = MyThread(i)
        t.start()
    

    运行结果:

    The arg is :0
    The arg is :2
    The arg is :1
    The arg is :3

    threading模块提供的常用方法:

    • threading.currentThread():返回当前的线程变量。
    • threading.enumerate():返回一个包含正在运行的线程的list。(正在运行的线程是指线程启动后,结束前,不包括启动前和终止后的线程。)
    • threading.active Count():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

    后台线程与前台线程

    is/setDeamon(bool):获取/设置是否为后台线程(默认为前台线程(False))。

    注: 在start()之前设置

    区别:

    1. 后台线程,主线程结束,后台线程立刻停止。
    2. 前台线程,主线程结束,等待前台线程执行完程序停止。

    相同点:

    ​ 不论是前台还是后台,在主线程运行时它们也运行。

    代码实例:

    if __name__ == '__main__':
        for i in range(4):
            t = MyThread(i)
            t.setDaemon(True)
            t.start()
    
        print('main thread end!')
    

    运行结果:

    main thread end!

    如果设置为前台线程,运行结果为:

    main thread end!
    The arg is :0
    The arg is :1
    The arg is :3
    The arg is :2

    join() 线程阻塞

    该方法会阻塞当前上下文环境线程,直到调用此方法的线程终止或者到达指定的timeout。即使设置了setDeamon(True)主线程依旧要等待子线程结束。

    ** 线程必须先start()然后再join()**

    代码实例:

    if __name__ == '__main__':
        th=[]
        for i in range(100):
            t = MyThread(i)
            th.append(t)
            t.start()
            ```
            不能直接写成t.join(),这样只会阻塞主线程一次,无法确保再阻塞过程中线程都执行完。
            下面的for循环时要阻塞主线程,创建的线程数那么多次,可以保证主线程最后执行完。
            这种不同于再上面的for循环里写join(),写在上面会使每个线程不光阻塞主线程,也阻塞接下来的线程。时多线程无意义。
            ```
        for tt in th:
            tt.join()
        #设置join之后,主线程等待子线程全部执行完成后或者子线程超时后,主线程才结束
        print('main thread end!')
    

    相关文章

      网友评论

          本文标题:2018-08-04(15.5)多线程

          本文链接:https://www.haomeiwen.com/subject/xywpvftx.html