Python-31-多线程

早过忘川 提交于 2019-11-26 19:50:42
  1. 并发

    并发: 多个事件在同一时间间隔内并发

    并行: 多个事件在同一时刻并行

    在多道程序处理时,宏观上并发,微观上交替执行(在单处理器情况下)

  2. 进程作为分配资源的基本单位,进程控制块 PCB,是线程的容器

    线程作为独立运行和独立调度的基本单位,进程实际的运作单位

    (线程有时称为轻量级进程,一个标准的线程由线程ID,当前指令指针,寄存器集合和堆栈组成.)

    (每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。即)

  3. Linux 父子进程,Windows进程平等

  4. 进程之间不共享数据,进程之间相互隔离

  5. 同一进程中的线程可共享进程的资源,每一个线程有自己独立的堆栈

  6. 执行队列(有顺序)、就绪队列(有顺序)、阻塞队列(无顺序)

    New 新建:新创建的线程经过初始化后,进入Runnable状态

    Runnable 就绪:等待线程调度,调度后进入运行状态

    Running 运行:线程正常运行

    Blocked 阻塞:暂停运行,解除阻塞后进入就绪队列

    Dead 消亡:线程方法执行完毕后返回或者异常终止

    [外链图片转存失败(img-nAEaRspG-1565419043715)(img/1-进程的五种基本状态及转换.png)]

    [外链图片转存失败(img-LFN3arpY-1565419043719)(img/2-挂起状态的进程状态转换图.png)]

    从执行状态进入阻塞状态:

    1. 同步:线程中获取同步锁,但是资源已经被其他线程锁定时,进入Locked状态,直到该资源可获取(获取的顺序由Lock队列控制)
    2. 睡眠:线程运行sleep()或join()方法后,线程进入Sleeping状态。区别在于sleep等待固定的时间,而join是等待子线程执行完。sleep()确保先运行其他线程中的方法。当然join也可以指定一个“超时时间”。从语义上来说,如果两个线程a,b, 在a中调用b.join(),相当于合并(join)成一个线程。将会使主调线程(即a)堵塞(暂停运行, 不占用CPU资源), 直到被调用线程运行结束或超时, 参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。最常见的情况是在主线程中join所有的子线程。
    3. 等待:线程中执行wait()方法后,线程进入Waiting状态,等待其他线程的通知(notify)。wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
  7. 单线程

     from time import sleep,ctime
     def music():
         for i in range(2):
             print('i am at music')
             sleep(1)
     def movie():
         for i in range(2):
             print('movie')
             sleep(5)
     
     # 主线程
     if __name__ == '__main__':
         music()
         movie()
         print('主线程main',ctime())
    
  8. 多线程

    多线程类似于同时执行多个不同程序

    Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装。

    任何进程默认就会启动一个线程,我们把该线程称为主线程,主线程又可以启动新的线程

  9. threading模块

    1. 提供的常量:

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

    2. 方法:

       threading.current_thread()  返回当前线程对象
       threading.active_count()    当前处于alive状态的线程个数
       threading.main_thread()     返回主线程对象
       threading.enumerate()       返回所以活着的线程列表
       threading.get_ident()       返回当前线程的ID,非0整数
      
    3. Thread实例(线程对象)的属性和方法

       name 只是一个名称标识,可以重名, getName()、setName()来获取、设置这个名词。
       ident 线程ID, 它是非0整数。线程启动后才会有ID,否则为None。线程退出,此ID依旧可以访问。此ID可以重复使用。
       is_alive() 返回线程是否活着
       
       isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。 
       get/setName(name): 获取/设置线程名。 
       start():  启动线程。每一个线程必须且只能执行该方法一次。线程准备就绪,等待CPU调度
       run(): 运行线程函数。
       join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。
      
  10. 开启线程

    Thread(target, group=None, name=None, args=(,), kwargs=None, * ,
    daemon=None)

    group:线程组

    target:线程调用的对象,就是目标函数名

    name:为线程起个名字

    args:为目标函数传递实参, 元组

    kwargs:为目标函数关键字传参, 字典

    # 创建线程、开启线程
    import threading
    from time import sleep
    lock = threading.Lock()
    def music():
        lock.acquire()
        print('i am at music')
        lock.release()
        sleep(1)
        lock.acquire()
        print('当前线程名字:{0}'.format(threading.current_thread()))
        lock.release()
        lock.acquire()
        print(threading.current_thread(),'->>>',threading.active_count())
        lock.release()
    
    for i in range(5):
        th = threading.Thread(target=music)
        th.start()
    
    lock.acquire()
    print('===========这是主线程=========')
    lock.release()
    
    
    # 开启线程传参
    import threading
    from time import sleep
    lock = threading.Lock()
    def music(i):
        lock.acquire()
        print('i am at music = ',i)
        lock.release()
        sleep(1)
        lock.acquire()
        print('当前线程名字:{0}'.format(threading.current_thread()))
        lock.release()
        lock.acquire()
        print(threading.current_thread(),'->>>',threading.active_count())
        lock.release()
    
    for i in range(5):
        th = threading.Thread(target=music, args=(i,))
        th.start()
    
    lock.acquire()
    print('===========这是主线程=========')
    lock.release()
    
  11. 线程退出

    python没有提供线程退出的方法,在下面情况时会退出:

    1. 线程函数内语句执行完毕.

    2. 线程函数中抛出未处理的异常.

       import threading
       from time import sleep
       def music(i):
           print('i am at music = ',i)
           try:
               if i == 3:
                   raise Exception('error i == 3')
           except IOError as ex:
               print(ex)
           print('当前线程名字:{0}'.format(threading.current_thread()))
           print(threading.current_thread(),'->>>',threading.active_count())
       
       for i in range(5):
           th = threading.Thread(target=music, args=(i,))
           th.start()
       
       
       print('===========这是主线程=========')
      
  12. Thread 的方法

    start():启动线程,调用run(),没调用start()则没启动线程,即不是多线程。每一个线程必须且只能执行该方法一次。

    run():运行进程,并没启动新线程

    start方法启动线程,启动了一个新的线程

    run方法启动的线程,并没有启动新的线程

  13. 继承线程类

    import threading
    from time import sleep
    lock = threading.Lock()
    class MyThread(threading.Thread):
        def __init__(self, target=None, name=None, args=None):
            super(MyThread, self).__init__(target=target, name=name, args=args)
            self.arg = args
        def start(self):
            print('start')
            super().start()
        def run(self):
            sleep(1)
            lock.acquire()
            print('arg:',self.arg)
            print(threading.current_thread())
            lock.release()
    
    th01 = MyThread(target=sleep,name='th01',args=(1,))
    th01.start()
    
    lock.acquire()
    print('个数:',threading.active_count())  # 如果是start(),输出2;如果是run(),输出1
    
    lock.release()
    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!