• 41 thread类 锁 事件 信号量 条件 定时器


    进程跟线程的执行效率对比

    同样任务线程的执行效率

    import time
    from threading import Thread
    from multiprocessing import Process
    # def  func(a):
    # a+=1
    #
    # if __name__ == '__main__':
    # start=time.time()
    # t1=[]
    # for i in range(50):
    # t=Thread(target=func,args=(i,)) #分出50个线程,来执行任务
    # t.start() #任务开始
    # t1.append(t) #
    # for t in t1:
    # t.join()
    # print("主线程")
    # print(time.time()-start)
    # statr=time.time()

    同样任务进程的执行效率

    import time
    from  threading  import Thread
    from  multiprocessing  import  Process
    
    def  func(a):
        a+=1
    
    if __name__ == '__main__':
        start=time.time()
        t1=[]
        for i in range(50):
            p=Process(target=func,args=(i,))
            p.start()
            t1.append(p)
        for  t in t1:
            t.join()
        print("主进程")
        print(time.time() - start)
    View Code

     # start     开始   join  等待
    # terminate   强制停止一个进程     在线程中没有

    线程之间的数据共享

    from  threading import Thread
    n=100
    def  func():
        global n
        n=n-1
    if __name__ == '__main__':
        t1=[]
        for i in range(100):
            t=Thread(target=func)
            t.start()
            t1.append(t)
        for  w  in  t1:
            t.join()
        print(n)
    View Code

    因为线程之间的数据是共享的,难免会造成数据混乱,所以用守护线程

    import time
    from threading import Thread
    def a1():
        while 1:
            print(True)
            time.sleep(0.5)
    def a2():
        print("in t2  start")
        time.sleep(3)
        print("in t2  end")
    if __name__ == '__main__':
        t1=Thread(target=a1)
        t1.setDaemon(True)
        t1.start()
        t2 = Thread(target=a2)
        t2.start()
        time.sleep(1)
        print("主线程")
    View Code

    主线程如果结束了 那么整个进程就结束
    守护线程 会等待主线程结束之后才结束.
         主进程 等待 守护进程 子进程
         守护进程 只守护主进程的代码就可以了
         守护线程不行 主线程如果结束了 那么整个进程就结束 所有的线程就都结束

    from threading import Thread,get_ident
    开启线程的第二种方式和查看线程id

    from threading import Thread,get_ident
    
    class MyThread(Thread):
        def __init__(self,args):
            super().__init__()
            self.args=args
    
        def run(self):
            print("in my thread:", get_ident(),self.args)
    
    print("main",get_ident())
    t=MyThread("wahaha") #主线程id
    t.start()  #子线程 id
    View Code

    线程中的方法

    Thread  开启一个线程

    get_ident  获得线程的运行id

    currentThread    给每个子线程一个名字 跟id

    enumerate,  正在运行的线程

    activeCount  正在运行的线程的数量 相当于len(enumerate())

    import time
    from threading import Thread,get_ident,currentThread,enumerate,activeCount
    # 开启线程的第二种方式和查看线程id
    class MyThread(Thread):
        def __init__(self,args):
            super().__init__()   # Thread类的init,在这个方法中做了很多对self的赋值操作,都是给创建线程或者使用线程的时候用的
            self.args = args
    
        def run(self):
            time.sleep(0.1)
            print(1)
            print(currentThread())
            print('in my thread : ',get_ident(),self.args)
    
    print('main',get_ident())
    t = MyThread('wahaha')
    # print(t.is_alive())
    t.start()
    print(activeCount())  # 正在运行的线程的数量 len(enumerate())
    # print(enumerate())
    # print('t : ',t)
    # print(t.is_alive())
    View Code

    # thread对象的其他方法 : isAlive ,setname,getname
    # threading模块的方法 : currentTread,activeCount,enumerate   

       =======================精讲join==========

    import time
    from threading import Thread
    from multiprocessing import Process
    
    def func():
        for i in range(5):
            print('in thread')
            time.sleep(0.2)
    
    if __name__ == '__main__':
        p_l = []
        for i in range(10):
            p = Process(target=func)
            p.start()
            p_l.append(p)
        p_l[0].join()   # 保证第0个进程结束了
        p_l[1].join()   # p1执行完了么?  执行完了就不阻塞
        p_l[2].join()   
        p_l[3].join()
        p_l[4].join()
        p_l[5].join()
        p_l[6].join()
        p_l[7].join()
        p_l[8].join()
        p_l[9].join()  # p9执行完了么 ?
            # p.join()   # 主进程被阻塞,等待p结束之后再继续往下执行
        for i in range(5):
            print('*'*10)
            time.sleep(0.2)
    View Code

    ==================锁===========

    在多个进程/线程同时访问一个数据的时候就会产生数据的不安全现象

    多进程 访问文件

    多线程 同时去访问一个数据

    GIL 全局解释器锁

      在同一个进程里的每一个线程同一时间只能有一个线程访问cpu

    尽量不要设置全局变量

    只要在多线程/进程之间用到全局变量  就加上锁

    from threading import Lock,Thread
    lock = Lock()
    lock.acquire()
    
    noodle = 100
    def func(name,lock):
        global noodle
        lock.acquire()
        noodle -= 1
        lock.release()
        print('%s吃到面了'%name)
    
    if __name__ == '__main__':
        lock = Lock()  # 线程锁 互斥锁
        t_lst = []
        for i in range(10):
            t = Thread(target=func,args=(i,lock))
            t.start()
            t_lst.append(t)
        for t in t_lst:
            t.join()
        print(noodle)
    View Code

    经典的科学家吃面问题   死锁

    import time
    from threading import Thread,Lock
    lock = Lock()
    noodle_lock = Lock()
    fork_lock = Lock()
    def eat1(name):
        noodle_lock.acquire()
        print('%s拿到了面' % name)
        fork_lock.acquire()
        print('%s拿到了叉子' % name)
        print('%s在吃面'%name)
        time.sleep(0.5)
        fork_lock.release()  # 0.01
        noodle_lock.release() # 0.01   
    
    def eat2(name):
        fork_lock.acquire()  # 0.01
        print('%s拿到了叉子' % name) # 0.01
        noodle_lock.acquire()
        print('%s拿到了面' % name)
        print('%s在吃面'%name)
        time.sleep(0.5)
        noodle_lock.release()
        fork_lock.release()
    
    eat_lst = ['alex','wusir','太白','yuan']
    for name in eat_lst:  # 8个子线程 7个线程 3个线程eat1,4个线程eat2
        Thread(target=eat1,args=(name,)).start()
        Thread(target=eat2,args=(name,)).start()
    """alex拿到了面
    alex拿到了叉子
    alex在吃面
    alex拿到了叉子
    wusir拿到了面    """
    View Code

    解决方案第一版

    import time
    from threading import Thread,Lock
    lock = Lock()
    def eat1(name):
        lock.acquire()
        print('%s拿到了面' % name)
        print('%s拿到了叉子' % name)
        print('%s在吃面'%name)
        time.sleep(0.5)
        lock.release() # 0.01
    
    def eat2(name):
        lock.acquire()  # 0.01
        print('%s拿到了叉子' % name) # 0.01
        print('%s拿到了面' % name)
        print('%s在吃面'%name)
        time.sleep(0.5)
        lock.release()
    
    eat_lst = ['alex','wusir','太白','yuan']
    for name in eat_lst:  # 8个子线程 7个线程 3个线程eat1,4个线程eat2
        Thread(target=eat1,args=(name,)).start()
        Thread(target=eat2,args=(name,)).start()
    View 解决方案第一版Code

    解决方案第二版

    import time
    from threading import Thread,RLock
    lock = RLock()
    def eat1(name):
        lock.acquire()
        print('%s拿到了面' % name)
        lock.acquire()
        print('%s拿到了叉子' % name)
        print('%s在吃面'%name)
        time.sleep(0.5)
        lock.release()  # 0.01
        lock.release() # 0.01
    
    def eat2(name):
        lock.acquire()  # 0.01
        print('%s拿到了叉子' % name) # 0.01
        lock.acquire()
        print('%s拿到了面' % name)
        print('%s在吃面'%name)
        time.sleep(0.5)
        lock.release()
        lock.release()
    
    eat_lst = ['alex','wusir','太白','yuan']
    for name in eat_lst:  # 8个子线程 7个线程 3个线程eat1,4个线程eat2
        Thread(target=eat1,args=(name,)).start()
        Thread(target=eat2,args=(name,)).start()
    View Code


    死锁:    多把锁同时应用在多个线程中
    互斥锁和递归锁哪个好
        递归锁 快速恢复服务
        死锁问题的出现 是程序的设计或者逻辑的问题
        还应该进一步的排除和重构逻辑来保证使用互斥锁也不会发生死锁
    互斥锁和递归锁的区别
         互斥锁 就是在一个线程中不能连续多次ACQUIRE
         递归锁 可以在同一个线程中acquire任意次,注意acquire多少次就需要release多少次

    ====================信号量=锁+计数器===============================

    import time
    from  multiprocessing  import Semaphore,Process,Pool
    def ktv1(sem,i):
        pass
    
    def ktv2(i):
        i+=1
    if __name__ == '__main__':
        sem=Semaphore(5)
        start=time.time()
        p1=[]
        for i in range(100):
            p=Process(target=ktv1,args=(sem,i))
            p.start()
            p1.append(p)
        for p  in p1:
            p.join()
        print("###",time.time()-start)
    
        start = time.time()
        p = Pool(5)
        p_l = []
        for i in range(100):
            ret = p.apply_async(func=ktv2, args=(sem, i))
            p_l.append(ret)
        p.close()
        p.join()
        print('***',time.time() - start)
    View Code

    池 效率高
        池子里有几个一共就起几个
        不管多少任务 池子的个数是固定的
         开启进程和关闭进程这些事都是需要固定的开销
         就不产生额外的时间开销
         且进程程池中的进程数控制的好,那么操作系统的压力也小
    信号量
         有多少个任务就起多少进程/线程
         可以帮助你减少操作系统切换的负担
         但是并不能帮助你减少进/线程开启和关闭的时间

    ==============事件===============================

    # wait
        # 等 到 事件内部的信号变成True就不阻塞了
    # set
        # 设置信号变成True
    # clear
        # 设置信号变成False
    # is_set
        # 查看信号是否为True

    实例代码  数据库连接

    import time
    # import random
    # from threading import Event,Thread
    # def check(e):
    #     '''检测一下数据库的网络和我的网络是否通'''
    #     print('正在检测两台机器之间的网络情况 ...')
    #     time.sleep(random.randint(0,2))
    #     e.set()
    #
    # def connet_db(e):
    #     n = 0
    #     while n < 3:
    #         if e.is_set():
    #             break
    #         else:
    #             e.wait(0.5)
    #             n += 1
    #     if n == 3:
    #         raise TimeoutError
    #     print('连接数据库 ... ')
    #     print('连接数据库成功~~~')
    #
    # e = Event()
    # Thread(target=connet_db,args=(e,)).start()
    # Thread(target=check,args=(e,)).start()
    View Code

    ===================条件======================

    from threading import Condition
    # acquire
    # release
    # wait    阻塞
    # notify  让wait解除阻塞的工具
    # wait还是notify在执行这两个方法的前后 必须执行acquire和release
    # from threading import Condition,Thread
    # def func(con,i):
    #     con.acquire()
    #     # 判断某条件
    #     con.wait()
    #     print('threading : ',i)
    #     con.release()
    #
    # con = Condition()
    # for i in range(20):
    #     Thread(target=func,args=(con,i)).start()
    # con.acquire()
    # # 帮助wait的子线程处理某个数据直到满足条件
    # con.notify_all()
    # con.release()
    # while True:
    #     num = int(input('num >>>'))
    #     con.acquire()
    #     con.notify(num)
    #     con.release()
    View Code

    ================定时器============

    from threading import Timer
    def func():
        print('执行我啦')
    
    # interval 时间间隔
    Timer(0.2,func).start()  # 定时器
    # 创建线程的时候,就规定它多久之后去执行
    View Code
  • 相关阅读:
    队列01--[队列&双端队列&循环队列&双端循环队列]
    LeetCode--[栈]--不定时更新
    栈01--[栈接口设计&&栈应用]
    初等数论初步
    成外国庆集训小记
    图论算法初步
    Are Lights Still On?
    二分答案和三分入门
    SCOI2010 传送带
    微信小程序 菜鸟笔记
  • 原文地址:https://www.cnblogs.com/daien522556/p/9391142.html
Copyright © 2020-2023  润新知