• 多线程


    # 图片  下载耗时 用多线程
    # threading模块
    import threading
    import time
    
    def coding():
        for i in range(3):
            print("正在写代码%s"%i)
            time.sleep(1)
    
    def drawing():
        for i in range(3):
            print("正在画画%s"%i)
            time.sleep(1)
    
    def main():
        # 创建一个子线程
        t1 = threading.Thread(target=coding, )
        t1.start()
        t2 = threading.Thread(target=drawing, )
        t2.start()
    
        
    if __name__ == '__main__':
        main()
    
    #####################################
    # 通过threading.current_thread() 获取当前的线程对象
    def coding():
        for i in range(3):
            print("正在写代码%s" % threading.current_thread())  
            time.sleep(1)
    
    def drawing():
        for i in range(3):
            print("正在画画%s" % threading.current_thread())
            time.sleep(1)
    # 使用Thread类创建多线程  
    # 区别就是继承一下threading.Thread, 把之前的函数的代码写到 def run下面
    
    import threading
    import time
    
    class CodingThread(threading.Thread):
        def run(self):
            for i in range(3):
                print("正在写代码%s"%threading.current_thread())
                time.sleep(1)
    
    class DrawingThread(threading.Thread):
        def run(self):
            for i in range(3):
                print("正在画画%s"%threading.current_thread())
                time.sleep(1)
    
    
    def main():
        # 创建一个子线程
        t1 = CodingThread()
        t1.start()
        t2 = DrawingThread()
        t2.start()
    
    
    if __name__ == '__main__':
        main()
    # 多线程共享全局变量 和 锁的问题(修改全局变量的时候要加锁,访问全局变量的不用加锁)
    # 线程执行的顺序是无序的
    
    import threading
    
    VALUE = 0
    gLock = threading.Lock() # 创建锁
    
    def add_value():
        global VALUE
        gLock.acquire() # 加锁
        for x in range(1000000):
            VALUE += 1
        gLock.release() # 解锁
        print("value,%d"%VALUE)
    
    def main():
        for x in range(2):
            t = threading.Thread(target=add_value)
            t.start()
    
    if __name__ == '__main__':
        main()
        
    # 加锁后执行结果,就不会有错误了
    # value,1000000
    # value,2000000
    # 不加锁的话两个线程会同时修改VALUE的数据, 相当于多线程同时对一个url 进行获取
    # Lock版的 生产者或消费者模式, 一般都是在多线程中才使用
    # 爬虫中生产者专门爬取url, 消费者专门解析url
    
    import threading
    import random
    import time
    
    gMoney = 1000
    gLock = threading.Lock()
    
    class Producer(threading.Thread):
        def run(self):
            global gMoney
            while True:
                money = random.randint(100,1000)
                gLock.acquire()
                gMoney += money
                print("%s生产了%d的钱,现在总共有%d"%(threading.current_thread(),money,gMoney))
                gLock.release()
                time.sleep(1)
    
    
    class Consumer(threading.Thread):
        def run(self):
            global gMoney
            while True:
                money = random.randint(100,1000)
                gLock.acquire()
                if gMoney >= money:
                    gMoney -= money
                    print("消费者%s,消费了%d,还剩有%d"%(threading.current_thread(),money,gMoney))
                else:
                    print("余额不足,当前金额是%d, 需要消费的金额是%d"%(gMoney,money))
                gLock.release()
                time.sleep(1)
    
    def main():
        for x in range(2):
            t = Producer(name="生产者%d"%x)
            t.start()
    
        for x in range(3):
            t = Consumer(name='消费者%d'%x)
            t.start()
    
    
    if __name__ == '__main__':
        main()
       
    # 以上是一个死循环模式 现在要求生产者只生产10次 就停止,
    # 消费者把已经生产出来的给消费掉, 消费完毕就停止消费
    # 相当于爬虫爬取一定个数的 url 就停止
    # 对上面代码修改
    
    import threading
    import random
    import time
    
    gMoney = 1000
    gLock = threading.Lock()
    gTimes = 0
    gTotalTimes = 10
    
    class Producer(threading.Thread):
        def run(self):
            global gMoney
            global gTimes
            global gTotalTimes
            while True:
                money = random.randint(100,1000)
                gLock.acquire()
    
                # if gTimes >= gTotalTimes:
                #     gLock.release()
                #     break
                # gMoney += money
                # gTimes += 1
                # print("%s生产了%d的钱,现在总共有%d" % (threading.current_thread(), money, gMoney))
                # gLock.release()
                # time.sleep(1)
    
                if gTimes < gTotalTimes:
                    gMoney += money
                    gTimes += 1
                    print("%s生产了%d的钱,现在总共有%d"%(threading.current_thread(),money,gMoney))
                    gLock.release()
                    time.sleep(1)
                else:
                    print("已经生产了10次, 停止生产")
                    gLock.release()
                    break
    
    
    class Consumer(threading.Thread):
        def run(self):
            global gMoney
            while True:
                money = random.randint(100,1000)
                gLock.acquire()
                if gMoney >= money:
                    gMoney -= money
                    print("消费者%s,消费了%d,还剩有%d"%(threading.current_thread(),money,gMoney))
                else:
                    if gTimes >= gTotalTimes:
                        gLock.release()
                        break
                    print("余额不足,当前金额是%d, 需要消费的金额是%d"%(gMoney,money))
                gLock.release()
                time.sleep(1)
    
    def main():
        for x in range(2):
            t = Producer(name="生产者%d"%x)
            t.start()
    
        for x in range(3):
            t = Consumer(name='消费者%d'%x)
            t.start()
    
    
    if __name__ == '__main__':
        main()
    
    # 面试题中有问 怎么确保多线程爬取的数据不会错乱? 可以使用这个 生产者消费者模式
    # 给多线程加锁之后, 保证同一个url 不会被爬取两次
    # condition版的生产者与消费者模式  比lock版本优化了
    # lock在while循环中 不断的加锁解锁, 消耗cup,所以不是最好的
    # threading.Condition 继承threading.Lock, 它可以在修改全局数据的时候加锁,在修改完毕后解锁
    
    # threading.Condition相关5个函数介绍:
    # acquire 上锁, 
    # release 解锁
    # wait 将当前线程处于等待状态(阻塞), 并且会释放锁,其他线程就可以使用锁了.
    # wait 函数可以被notify和notify_all函数唤醒, wait被唤醒后等待上锁, 上锁后继续执行下面代码
    # notify 通知某个等待的线程,默认是第一个等待的线程.告诉等待的线程可以去获取锁了
    # notify_all 通知所有正在等待的线程. notify和notify_all不会释放锁,需要在release之前使用
    
    # threading.Condition 继承threading.Lock
    import threading
    import random
    import time
    
    gMoney = 1000
    gCondition = threading.Condition()
    gTimes = 0
    gTotalTimes = 10
    
    class Producer(threading.Thread):
        def run(self):
            global gMoney
            global gTimes
            global gTotalTimes
            while True:
                money = random.randint(100,1000)
                gCondition.acquire()
                if gTimes >= gTotalTimes:
                    gCondition.release()
                    break
    
                gMoney += money
                gTimes += 1
                print("%s生产了%d的钱,现在总共有%d" % (threading.current_thread(), money, gMoney))
                gCondition.notify_all() #通知wait等待的线程
                gCondition.release()
                time.sleep(1)
    
    
    class Consumer(threading.Thread):
        def run(self):
            global gMoney
            while True:
                money = random.randint(100,1000)
                gCondition.acquire()
    
                while gMoney < money: 
                # 被等待的线程被唤醒后,又去线程队列中排队,但是排到的时候钱又不足了
                    if gTimes > gTotalTimes:
                        gCondition.release()
                        return #直接跳出两个 while 循环
                    
                    print("%s,准备消费%d,剩余金额%d,金额不足,继续等待!!!" % (threading.current_thread, money, gMoney))
                    gCondition.wait()
    
                gMoney -= money
                print("消费者%s,消费了%d,剩余金额%d"%(threading.current_thread,money,gMoney))
                gCondition.release()
                time.sleep(1)
    
    def main():
        for x in range(2):
            t = Producer(name="生产者%d"%x)
            t.start()
    
        for x in range(3):
            t = Consumer(name='消费者%d'%x)
            t.start()
    
    
    if __name__ == '__main__':
        main()
    # Queue线程安全队列   线程安全的时候就不用加锁了
    '''
    在线程中,访问一些全局变量,加锁是一个经常的过程. 如果想把一些数据存储到某个队列中,那么python内置了一个线程安全的模块叫做queue模块.
    python中的queue模块提供了同步的,线程安全的队列类,包括FIFO先进先出队列Queue,
    LIFO后进先出队列LifeQueue.
    这些队列实现了锁原理(可以理解为原子操作,要么都改,要么都不改),能够在多线程中直接使用,可以使用队列实现线程间的同步.
    
    相关函数:
    1.初始化 Queue(maxsize)创建一个先进先出的队列
    2.qsize() 返回队列的大小,有多少个元素
    3.empty() 判断队列是否为空
    4.full() 判断队列是否满
    5.get() 从队列中获取最后一个
    6.put() 将一个数据放到队列中
    
    q.get(block=True) 如果队列当中没有值就一直阻塞在这里,默认是True
    q.put(block=True) 表示如果给队列添加值,如果队列是满的就一直等待着
    '''
    
    from queue import Queue
    
    q = Queue(3)
    q.put(2)
    q.put(1)
    q.put(3)
    
    print(q.qsize()) # 3
    print(q.full())  # true
    print(q.empty()) # false
    print(q.get())   # 2
    ##########################################
    from queue import Queue
    import time
    import threading
    
    def set_value(q):
        index = 0
        while True:
            q.put(index)
            index += 1
            time.sleep(3)
    
    def get_value(q):
        while True:
            print(q.get())
    
    def main():
        q = Queue(4)
        t1 = threading.Thread(target=set_value,args=[q])
        t2 = threading.Thread(target=get_value,args=[q])
        t1.start()
        t2.start()
    
    if __name__ == '__main__':
        main()
    
    # set_value是每隔3秒产生一个
    # get_value是一直在取,如果队列中没有就等着
  • 相关阅读:
    33. 搜索旋转排序数组
    54. 螺旋矩阵
    46. 全排列
    120. 三角形最小路径和
    338. 比特位计数
    746. 使用最小花费爬楼梯
    spring boot的一些常用注解
    SSM整合Dubbo案例
    一些面试题
    Spring Aop和Spring Ioc(二)
  • 原文地址:https://www.cnblogs.com/kenD/p/11123681.html
Copyright © 2020-2023  润新知