zoukankan      html  css  js  c++  java
  • 线程与子线程(python3入门)

    一、线程的概述

    进程的缺点:
        1. 非常消耗资源,所以每次'主线程...'会先与子进程之前进行打印,一次我            们的子进程不能无限的打开
        2. 如果开了过多的子进程,cpu在进程的模式下切来切去是非常耗费时间的
    
    因此引入线程:
        线程的出现,实就是要解决上面的两个问题
        轻量级的进程====> 线程
    线程VS进程:
        - 线程是一个轻量级的进程
        - 一个进程里面至少有一个线程, 可以有多个线程
        - 线程是具体干活的
    
    线程的好处:
        - 线程开启速度快于进程
        - 线程之间的数据是共享的
        - CPU在线程之间的切换速度远快于进程
    
    使用的场景(进程线程)
        线程: 有大量IO存在的时候,使用线程
        
        进程: 有密集计算的时候使用
    
    同一个进城之间的数据在线程之间的是共享的

    二、开启线程的两种方式

    # 方式一:使用函数的方式开启
    # from threading import Thread
    # import time
    #
    # def task(arg):
    #     print('%s is running...'% arg)
    #     time.sleep(1)
    #     print('%s is done...'% arg)
    #
    # if __name__ == '__main__':
    #     t = Thread(target=task, args=('子线程',))
    #     t.start()   #开启的瞬间就执行了子线程的所有内容
    #
    #     print('主线程..')
    方式一(函数型)
    # 方式二:类的方式开启
    from threading import Thread
    import time
    
    class MyThread(Thread):
        def run(self):
            print('%s is running...'% self)
            time.sleep(1)
            print('%s is done...'% self)
    
    if __name__ == '__main__':
            t = MyThread()
            t.start()
            print('主线程...')
    方式二(类)

    三、同一进程下,线程的数据是共享的

    from threading import Thread
    
    x = 100
    
    def task():
        global x
        x = 0
    
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
    
        print(x)    #结果x=0, 数据是共享的
    View Code

    四、进程和线程的执行速度对比

    from threading import Thread
    from multiprocessing import Process
    import time
    
    def task(arg):
        print('%s is running...'% arg)
        time.sleep(1)
        print('%s is done...'% arg)
    
    if __name__ == '__main__':
        p = Process(target=task, args=('子进程',))
        p.start()
    
        t = Thread(target=task, args=('子线程',))
        t.start()   #开启的瞬间就执行了子线程的所有内容
    
        print('主线程..')
    线程的运行速度要远快于进程

    五、线程的其他属性

    # 例1:
    # from threading import Thread
    # import time
    #
    # def task():
    #     print('xxxx')
    #
    # if __name__ == '__main__':
    #     t = Thread(target=task)
    #     t.start()
    #     t.join()    #等待子线程执行完毕
    #     print(t.is_alive()) #判断子线程是否存活
    #     print('主线程...')
    
    
    # 例2:计算10个子线程运行的时间总和
    import time
    from threading import Thread
    
    def task():
        print('xxx')
        time.sleep(1)
    
    if __name__ == '__main__':
    
        start = time.time()
        t_l = []
    
        for i in range(10):
            t = Thread(target=task)
            t_l.append(t)
            t.start()
    
        for t in t_l:
            t.join()
    
        print('子线程总运行时间为%s'%(time.time()-start))
        print(t_l)
    join(),is_alive()

    六、守护线程

    # 守护线程例1:
    # 结论:当其他非守护线程执行完毕时,开启守护线程的子线程也随之结束
    from threading import Thread
    from threading import current_thread
    import time
    
    
    def task():
        print('%s is running...'% current_thread().name)
        time.sleep(3)
        print('%s is done...'% current_thread().name)
    
    if __name__ == '__main__':
        t = Thread(target=task, name='守护线程')
        t.daemon = True
        t.start()
        print('主线程...')
    守护线程例1
    # 守护线程例2:
    # 结论:当其他非守护线程执行全部完毕时,开启守护线程的子线程才随之结束
    from threading import Thread
    import time
    
    def foo():
        print(123)
        time.sleep(3)
        print('end123')
    
    def bar():
        print(456)
        time.sleep(1)
        print('end456')
    
    t1 = Thread(target=foo)
    t2 = Thread(target=bar)
    
    t2.daemon = True
    
    t1.start()
    t2.start()
    
    print('主线程...')
    守护线程例2
    # 守护进程例1
    # 结论:当某个子进程开启了守护进程时,当父进程执行完毕时,该子进程也随之结束
    from multiprocessing import Process
    import time
    
    
    def foo():
        print(123)
        time.sleep(3)
        print('end123')
    
    def bar():
        print(456)
        time.sleep(1)
        print('end456')
    
    p1 = Process(target=foo)
    p2 = Process(target=bar)
    
    p1.daemon = True
    # p2.daemon = True
    
    p1.start()
    p2.start()
    
    print('主线程...')
    守护进程例子(与守护线程进行比较)

    七、线程的互斥锁

    # 例1: 线程运行速度太快了,导致数据失真(因为100个线程同时去拿x的时候得到x的值均为100。。。所以导致该例子的结打印x的时候值为99)
    # from threading import Thread
    # import time
    #
    # x = 100
    #
    # def task():
    #     global x
    #     tmp = x
    #     time.sleep(0.1)   #模拟网络延迟
    #     x = tmp - 1
    #
    #
    #
    # if __name__ == '__main__':
    #     t_l = []
    #
    #     for i in range(100):
    #         t = Thread(target=task,)
    #         t_l.append(t)
    #         t.start()
    #
    #     for j in t_l:
    #         j.join()
    #
    #     print(x)
    没有开启线程互斥锁的案例(会引起数据错乱失真)
    # 例2: 使用线程互斥锁后的优化效果
    # 线程的互斥锁基本和进程的互斥锁效果一致,(而进程是from multiprocess import Lock)
    from threading import Thread
    from threading import Lock
    import time
    
    
    mutex = Lock()
    x = 100
    
    def task():
        global x
    
        mutex.acquire() #获得锁,加一把锁
    
        tmp = x
        # time.sleep(0.1)
        x = tmp - 1
    
        mutex.release() #释放锁
    
    
    
    if __name__ == '__main__':
        t_l = []
    
        for i in range(100):
            t = Thread(target=task,)
            t_l.append(t)
            t.start()
    
        for j in t_l:
            j.join()
    
        print(x)
    开启线程互斥锁后(数据的使用恢复秩序井然)

    八、线程的死锁和递归锁

    例1: 下列代码进入了一个递归死锁的状态
    from threading import Thread
    from threading import Lock
    import time
    
    
    
    mutexA = Lock()
    mutexB = Lock()
    
    class MyThread(Thread):
    
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s 拿到了A锁'% self.name)
    
            mutexB.acquire()
            print('%s 拿到了B锁'% self.name)
    
            mutexA.release()
            mutexB.release()
    
        def f2(self):
            mutexB.acquire()
            print('%s 拿到了B锁'% self.name)
            time.sleep(1)
    
            mutexA.acquire()
            print('%s 拿到了A锁'% self.name)
    
            mutexB.release()
            mutexA.release()
    
    if __name__ == '__main__':
        for i in range(10):
            t = MyThread()
            t.start()
    未开启线程递归锁Rlock,代码进入递归死锁的状态
    # 例:使用递归锁Rlock 来解决上例的问题
    from threading import Thread
    from threading import Lock
    from threading import RLock
    import time
    
    
    
    obj = RLock()   #可以连续的acquire()
    
    
    # mutexA = Lock()
    # mutexB = Lock()
    
    mutexA = obj
    mutexB = obj
    
    
    class MyThread(Thread):
    
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s 拿到了A锁'% self.name)
    
            mutexB.acquire()
            print('%s 拿到了B锁'% self.name)
    
            mutexA.release()
            mutexB.release()
    
        def f2(self):
            mutexB.acquire()
            print('%s 拿到了B锁'% self.name)
            time.sleep(1)
    
            mutexA.acquire()
            print('%s 拿到了A锁'% self.name)
    
            mutexB.release()
            mutexA.release()
    
    if __name__ == '__main__':
        for i in range(10):
            t = MyThread()
            t.start()
    当开启线程递归锁Rlock后,代码继续运行下去了

    九、线程的信号量

    from threading import Thread
    from threading import Semaphore
    from threading import current_thread
    import time
    import random
    
    
    sema = Semaphore(5) #表示每次里面只有5个坑位
    
    def task():
        with sema:
            print('%s 正在上厕所' % current_thread().name)
            time.sleep(random.randint(1,3))
    
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=task,)
            t.start()
    线程的信号量示例

    十、线程池(py3中引入了新的整合包)

    线程池的使用

    import time
    import os
    from concurrent.futures import ThreadPoolExecutor   #引入线程池
    from concurrent.futures import ProcessPoolExecutor  #引入进程池
    
    # 进程池和线程池的使用方法一模一样
    # 下例为线程池的示例
    
    def task(i):
        print(i)
        time.sleep(1)
    
    
    if __name__ == '__main__':
        '''
        建议开启线程池的个数 = cpu个数*5
        '''
        # print(os.cpu_count())   #4个
        t = ThreadPoolExecutor(20)  #在线程池子里面放了20个线程
    
        res_li = []
    
        for i in range(30):
            res = t.submit(task, i )  # 和start一致,就是开始执行的意思
            res_li.append(res)
    
        t.shutdown()    #合并了进程池中的close + join的工作,作用就是停止提交任务,并等待子线程执行完毕
    
        for res in res_li:
            res.result()    #类似appy_async中的get()
    线程池(在这个包内,进程池的使用方法和进程池一致)
  • 相关阅读:
    WLAN设备接入过程
    802.1帧格式、帧类型详解
    SSID、BSSID、BSS等区分
    802.11协议详解
    bit、Byte、Mbps、Mb/s区别
    WLAN认证技术
    freemarker的简单使用案例
    关于throw、throws、try--catch的问题
    String去重方法
    常用典型的sql语句
  • 原文地址:https://www.cnblogs.com/lich1x/p/10359084.html
Copyright © 2011-2022 走看看