zoukankan      html  css  js  c++  java
  • 多线程实现生产者消费者

    1. Python多线程介绍

    Python提供了两个有关多线程的标准库,thread和threading。thread提供了低级别的,原始的线程和一个锁。threading则是一个高级模块,提供了对thread的封装。一般情况下,使用threading是比较好的做法。
    使用threading实现线程,只需要从threading.Thread类继承,并重写其中的__init__()方法和run()方法。

    from threading import Thread 
    
    class MyThread(Thread): 
        def __init__(self): 
            Thread.__init__(self) 
        def run(self): 
            print(self.thread_id, "start")
    

     threading提供了一个锁:lock = threading.Lock(),调用锁的acquire()和release()方法可以使线程获得和释放锁。

    需要注意的是,Python有一个GIL(Global Interpreter Lock)机制,任何线程在运行之前必须获取这个全局锁才能执行,每当执行完100条字节码,全局锁才会释放,切换到其他线程执行。

    所以Python中的多线程不能利用多核计算机的优势,无论有多少个核,同一时间只有一个线程能得到全局锁,只有一个线程能够运行。

    那么Python中的多线程有什么作用呢?为什么不直接使用Python中的多进程标准库?这里要根据程序执行的是IO密集型任务和计算密集型任务来选择。

    当执行IO密集型任务时,比如Python爬虫,大部分时间都用在了等待返回的socket数据上,CPU此时是完全闲置的,这种情况下采用多线程较好。

    当执行计算密集型任务时,比如图像处理,大部分时间CPU都在计算,这种情况下使用多进程才能真正的加速,使用多线程不仅得不到并行加速的效果,反而因为频繁切换上下文拖慢了速度。

    2. threading实现生产者消费者

    from threading import Thread
    import time
    
    queue = []
    class Producer(Thread):
        def __init__(self,name):
            Thread.__init__(self)  #调用未绑定的超类构造方法【必须显式调用父类的构造方法,否则不会执行父类构造方法,这个跟Java不一样】
            self.name = name
        def run(self):
            while True:
                queue.append(1)
                print("Producer: %s create a product" % self.name)
                print("Producer: %s put a product into queue" % self.name)
                time.sleep(0)
                if len(queue) > 20:
                    print ("queue is full!")
                    time.sleep(1)
    class Consumer(Thread):
        def __init__(self,name):
            Thread.__init__(self)
            self.name = name
        def run(self):
            while True:
                try:
                    queue.pop()
                    print("Consumer: %s get a product" % self.name)
                    time.sleep(2)
                except:
                    print("Queue is empty!")
                    time.sleep(2)
                    print("Consumer: %s sleep 2 seconds" % self.name)
    
    if __name__ == '__main__':
        p1 = Producer("Producer-1")
        c1 = Consumer("Consumer-1")
        c2 = Consumer("consumer-2")
    
        p1.start()
        c1.start()
        c2.start()
    

     输出如下:

    Producer: Producer-1 create a product
    Producer: Producer-1 put a product into queue
    queue is full!
    Producer: Producer-1 create a product
    Producer: Producer-1 put a product into queue
    queue is full!
    

     分析:输出显示满了之后仍然显示了生产者在创建产品,表明线程run()方法中的运行次序被打乱了。这是因为没有加锁,导致消费者线程运行到一半的时候,生产者线程获得了CPU。

    queue线程安全容器

    Python提供了Queue这一线程安全的容器,可以方便的和多线程结合起来。 Queue包括:
    FIFO先入先出队列Queue
    LIFO后入先出队列LifoQueue
    优先级队列PriorityQueue
    这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。
    queue_tmp = Queue.Queue(10)
    
    class Producer(Thread):
        def __init__(self,name):
            Thread.__init__(self)  #调用未绑定的超类构造方法【必须显式调用父类的构造方法,否则不会执行父类构造方法,这个跟Java不一样】
            self.name = name
        def run(self):
            while True:
                queue_tmp.put(0)
                print("Producer: %s create a product" % self.name)
                print("Producer: %s put a product into queue
    " % self.name)
    
    class Consumer(Thread):
        def __init__(self,name):
            Thread.__init__(self)
            self.name = name
        def run(self):
            while True:
                queue_tmp.get()
                print("Consumer: %s get a product" % self.name)
    

    3. join()函数用法测试

    join()函数的原型是join(timeout=None),它的作用是阻塞进程一直到线程退出或者到timeout的时间结束。

    参考文章:https://www.jianshu.com/p/f09a112a71f7

  • 相关阅读:
    Spring事务配置的五种方式(转)
    struts.properties配置详解(转)
    Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法(转)
    php的ob函数实现页面静态化
    冒泡排序法原理讲解及PHP代码示例
    Linux Centos下编译安装Redis
    PHP判断是手机端还是PC端
    windows 下 Symfony的下载与安装
    JS在线生成二维码
    关于微信分享到朋友圈(Thinkphp-tp3.2框架下实现)
  • 原文地址:https://www.cnblogs.com/honey-badger/p/8454873.html
Copyright © 2011-2022 走看看