zoukankan      html  css  js  c++  java
  • 多线程

    # 图片  下载耗时 用多线程
    # 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是一直在取,如果队列中没有就等着
  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/kenD/p/11123681.html
Copyright © 2011-2022 走看看