zoukankan      html  css  js  c++  java
  • Day036--Python--线程

    1. 线程

      

    from threading import Thread
    
    def func(n):
        print(n)
    
    if __name__ == '__main__':
        t = Thread(target=func, args=(3,))
        t.start()
        print('主线程结束')
    View Code创建进程方法一
    from threading import Thread
    
    class MyThread(Thread):
        def run(self):
            print('XXX')
    
    if __name__ == '__main__':
        t = MyThread()
        t.start()
        print('主线程结束')
    View Code创建进程方法二

    2. 线程和进程的效率对比

      线程的效率非常高, 而且线程的开启不需要消耗资源

    import time
    from threading import Thread
    from multiprocessing import Process
    
    def func(n):
        num = 0
        for n1 in range(n):    # 做个运算, 消耗一下时间, 好比较线程与进程的效率
            num += n1
        print('num', num)
    
    if __name__ == '__main__':
        t_s_t = time.time()   # 线程运行起始时间
        tlst = []
        for i in range(10):
            t = Thread(target=func, args=(10,))
            t.start()
            tlst.append(t)
        [t.join() for t in tlst]   # 迭代着join等待线程全部运行完毕
        t_e_t = time.time()      # 线程运行结束时间
        t_dif_t = t_e_t - t_s_t   # 计算线程的运行时间差
        
        print('线程的结束时间', t_dif_t)
        p_s_t = time.time()
        plst = []
        for i in range(10):
            p = Process(target=func, args=(10,))
            p.start()
            plst.append(p)
        [p.join() for p in plst]
    
        p_e_t = time.time()
        p_dif_time = p_e_t - p_s_t
        print('进程的结束时间', p_dif_time)
        print('主线程结束', t_dif_t)

    3. 线程之间数据共享

    from threading import Thread
    
    num = 100
    def func():
        global num
        num = 0
    
    if __name__ == '__main__':
        t = Thread(target=func)
        t.start()
        print(num)
        t.join()
        print('主线程结束')
    View Code 线程间数据共享
    import time
    import random
    from threading import Thread
    
    n = 100
    def func():
        global n
        x = n
        x = x - 1
        time.sleep(random.random())
        n = x
    
    if __name__ == '__main__':
    
        for i in range(30):
            t_lst = []
            for i in range(10):
                t = Thread(target=func)
                t.start()
                t_lst.append(t)
            # [t.join() for t in t_lst]
            print(n)
    View Code 数据共享, 不安全
    import time
    from threading import Thread, Lock
    
    num = 100
    def func(t_lock):
        global num
        t_lock.acquire()
        mid = num
        mid = mid - 1
        time.sleep(0.0000001)
        num = mid
        t_lock.release()
    
    if __name__ == '__main__':
        t_lock = Lock()
        t_lst = []
        for i in range(10):
            t = Thread(target=func, args=(t_lock,))
            t.start()
            t_lst.append(t)
        [t.join() for t in t_lst]
    
        print('主线程>>>', num)
    View Code 共享数据加锁保障安全

    4. 锁(同步锁/互斥锁) 

      1. GIL (Global Interpreter Lock) 全局解释锁

      2. Lock  同步锁/互斥锁

      3. RLock  递归锁

      保证数据安全, 但是牺牲了效率, 同步执行锁内代码

      死锁现象: 当我们使用锁嵌套锁时, 多个线程异步执行的时候会出现线程之间相互争夺对方未释放的锁, 相互等待.   (互相抢到了对方需要的锁, 导致双方相互等待, 程序没法进行)

    import time
    from threading import Thread, Lock
    
    class MyThread(Thread):
    
        def __init__(self, lockA, lockB):
            super().__init__()
            self.lockA = lockA
            self.lockB = lockB
    
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            self.lockA.acquire()
            print('我拿了A锁')
            self.lockB.acquire()
            print('我拿了B锁')
            print('我是f1')
            self.lockB.release()
            self.lockA.release()
    
        def f2(self):
            self.lockB.acquire()
            time.sleep(1)
            print('拿到了B锁')
            self.lockA.acquire()
            print('拿到了A锁')
            print('我是f2')
            self.lockA.release()
            self.lockB.release()
    
    if __name__ == '__main__':
        lockA = Lock()
        lockB = Lock()
        t1 = MyThread(lockA, lockB)
        t1.start()
    
        t2 = MyThread(lockA, lockB)
        t2.start()
    
        print('我是主线程')
    View Code 死锁现象

       

      解决死锁: 递归锁 RLock   可以多次acquire, 通过一个计数器来记录被锁了多少次, 只有计数器为0的时候, 大家才能继续抢锁.

    import time
    from threading import Thread, Lock, RLock
    
    
    class MyThread(Thread):
    
        def __init__(self, lockA, lockB):
            super().__init__()
            self.lockA = lockA
            self.lockB = lockB
    
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            self.lockA.acquire()
            print('我拿了A锁')
            self.lockB.acquire()
            print('我拿了B锁')
            print('我是f1')
            self.lockB.release()
            self.lockA.release()
    
        def f2(self):
            self.lockB.acquire()
            time.sleep(1)
            print('拿到了B锁')
            self.lockA.acquire()
            print('拿到了A锁')
            print('我是f2')
            self.lockA.release()
            self.lockB.release()
    
    
    if __name__ == '__main__':
        lockA = lockB = RLock()
        t1 = MyThread(lockA, lockB)
        t1.start()
    
        t2 = MyThread(lockA, lockB)
        t2.start()
    
        print('我是主线程')
    View Code 递归锁, 解决死锁

     经典问题: 科学家吃面

    import time
    from threading import Thread,Lock, RLock
    
    def eat1(name, lockA, lockB):
        lockA.acquire()
        print('%s抢到了叉子' % name)
        lockB.acquire()
        print('%s抢到了面条' % name)
        print('%s开始吃面啦~~' % name)
        lockB.release()
        lockA.release()
    
    
    def eat2(name, lockA, lockB):
        lockB.acquire()
        print('%s抢到了面条' % name)
        time.sleep(1)
        lockA.acquire()
        print('%s抢到了叉子' % name)
        print('%s开始吃面啦~~~' % name)
        lockA.release()
        lockB.release()
    
    if __name__ == '__main__':
        lockA = lockB = RLock()
        # lockA = Lock()
        # lockB = Lock()
        for name in ['alex', 'wu sir', 'boss king', 'taibai']:
            t1 = Thread(target=eat1, args=(name, lockA, lockB))
            t1.start()
            t2 = Thread(target=eat2, args=(name, lockA, lockB))
            t2.start()
    View Code死锁和递归锁解决死锁

           

    5. 守护线程 

      主进程代码结束程序并没有结束,并且主进程还存在,进程等待其他的子进程执行结束以后,为子进程收尸,注意一个问题:主进程的代码运行结束守护进程跟着结束,

    守护线程:

      主线程等待所有非守护线程的结束才结束,主线程的代码运行结束,还要等待非守护线程的执行完毕.这个过程中守护线程还存在

    import time
    from multiprocessing import Process
    from threading import Thread
    
    def func(n):
        time.sleep(5)
        print(n)
    
    if __name__ == '__main__':
        # 主线程等待的是子线程的任务全部执行完毕
        t = Thread(target=func, args=('我是子线程',))
        t.start()
        # 主进程等待的是给子进程收尸, 回收资源,各种信息
        # p = Process(target=func, args=('我是子进程',))
        # p.start()
        print('主线程结束')
    View Code 主线程等待子线程的原因
    import time
    from multiprocessing import Process
    from threading import Thread
    
    def func1(n):
        time.sleep(5)
        print(n)
    
    def func2(n):
        time.sleep(2)
        print(n)
    
    if __name__ == '__main__':
        # p1 = Process(target=func1, args=('我是1号',))
        # p1.daemon = True
        # p1.start()
        # p2 = Process(target=func2, args=('我是2号',))
        # p2.start()
        t1 = Thread(target=func1, args=('我是1号',))
        # t1.daemon = True
        t1.start()
        t2 = Thread(target=func2, args=('我是2号',))
        t2.daemon = True  # 等待所有非守护线程结束
        t2.start()
    
        print('主线程结束')  # 守护进程在主进程运行代码结束时跟着结束, 不会跟着其他子进程执行
    View Code 守护线程与守护进程差别

      

    6. 信号量

      控制同时能够进入锁内去执行代码的线程数量(进程数量), 维护了一个计数器, 刚开始创建信号量的时候, 假如设置的是4个房间, 进入一次acquire就减1, 出来一个就+1, 如果计数器为0, name其他的任务等待, 这样其他的任务和正在执行的任务是一个同步的状态, 而进入acquire里面去执行的那4个任务是异步执行的.

    # 和进程中信号量的按摩房一个道理, 相当于有多把锁
    import time
    from threading import Thread, Semaphore
    
    def func1(s):
        s.acquire()
        time.sleep(1)
        print('你好啊')
        s.release()
    
    if __name__ == '__main__':
        s = Semaphore(4)
        for i in range(10):
            t = Thread(target=func1, args=(s,))
            t.start()

    超哥博客--Python之线程

  • 相关阅读:
    Oracle数据库导入(数据泵导)
    C# 根据WCF 的url动态调用WCF
    winform嵌套浏览器
    微信支付服务商模式 配置
    结对项目-增强型科学计算器
    vscode编辑远程linux系统下c/c++代码实现代码补全
    Linux development with C++ in Visual Studio
    用VS2015开发Linux程序详细教程-配置篇
    Go语言环境搭建详解(2020版)
    bat脚本实现后台运行cmd命令
  • 原文地址:https://www.cnblogs.com/surasun/p/9855334.html
Copyright © 2011-2022 走看看