zoukankan      html  css  js  c++  java
  • 生产者消费者模型;线程知识点汇总

    '''
    生产者消费者模型:
    为什么要使用生产者和消费者模式?
       在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就
    必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
    什么是生产者消费者模式?
       生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完
    数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
    '''
    
    import time, threading, queue, random
    
    q = queue.Queue()
    
    def Producer(name):
       count = 1
       while count<11:
          print('%s厨师做包子中...' % name)
          time.sleep(random.randrange(4))
          q.join() # ②等待消费者的q.task_done(),当消费者线程停了,那么生产者的q.join()也收不到任何消息,所以程序卡住了
          q.put(count)
          # q.task_done() # ①
          print('%s厨师做好了第%s个包子!' % (name, count))
          count += 1
    
    def Cousumer(name):
       count = 1
       while count<11:
          time.sleep(random.randrange(4))
          # if not q.empty():
          #  data = q.get()
          #  print('33[1;31;43m%s吃了第%s个包子33[0m' % (name, data))
          # else:
          #  print('33[1;33;41m%s说没包子了,厨师你快一点行不行啊?33[0m' % name)
    
          # q.join() # ①如果其它线程没有q.task_done(),那么这个线程会一直卡在这里,不会往下执行
          data = q.get()
          q.task_done()  #
          print('33[1;31;43m%s吃了第%s个包子33[0m' % (name, data))
          count += 1
    
    p1 = threading.Thread(target=Producer, args=('威猛',))
    c1 = threading.Thread(target=Cousumer, args=('孙俪',))
    # c2 = threading.Thread(target=Cousumer, args=('小雯',))
    # c3 = threading.Thread(target=Cousumer, args=('李华',))
    
    p1.start()
    c1.start()
    # c2.start()
    # c3.start()
    
    '''Python输出带颜色字体详解:https://www.cnblogs.com/daofaziran/p/9015284.html'''
    
    
    '''进程和线程
    进程:
      本质上就是一段程序的运行过程(抽象的概念)
    进程定义:
      进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。
      我们编写的程序用来描述进程要完成哪些功能以及如何完成;
      数据集则是程序在执行过程中所需要使用的资源;
      进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
    线程:
      线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。
    线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。线程没有自己的系统资源。
    线程进程的关系区别:
      1、一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器)
      2、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
      3、线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
      4、进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行
    中必不可少的资源(如程序计数器,一组寄存器和栈)但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
      一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
    
    **************线程threading模块**************
    开启线程:t=threading.Thread(target=x, args=())或者自定义一个类继承threading.Thread并且重写run方法;t.start()开启
    
    join方法:在子线程完成运行之前,这个子线程的父线程将一直被阻塞,阻塞并不是退出---实例调用t.join()
    
    setDaemon(True)方法:将线程声明为守护线程,必须在start()方法调用之前设置;不管子线程是否完成,主线程退出了就跟着退出---t.setDaemon(True)
    
    其它方法:t.is_alive判断线程是否在运行
    
    并发:是指系统具有处理多个任务(动作)的能力
    并行:是指系统具有同时处理多个任务(动作)的能力;并行是并发的一个子集
    同步:当进程执行到一个IO(等待外部数据)的时候,需要等;这就叫同步;比如recv,accept
    异步:当进程执行到一个IO(等待外部数据)的时候,不需要等;一直等到数据接收成功,再回来处理;这就叫异步
    GIL的概念:python的GIL,意思就是说每一个进程都有一把GIL锁,也就是cpu只执行一个进程,然后进程间每个线程不断切换让cpu执行,大量的切换也需要消耗时间
    
    同步锁Lock:l=threading.Lock()---l.acquire()---l.release();多把锁的情况很容易造成死锁
    
    递归锁RLock:rl=threading.RLock()---rl.acquire()---rl.release();上了多少把递归锁就得释放多少把递归锁,只有等锁全部释放完后才切换执行
    
    同步条件Event:e=threading.Event()---e.wait()Event状态值为False线程阻塞True则执行---e.set()设置Event状态值为True且所有阻塞池的线程激活等待系统调度---e.clear()恢复Event状态值为False---e.isSet()返回Event状态值
    
    信号量Semaphore:s=threading.Swmaphore(5);一个信号量管理一个内部计数器,该计数器因acquire()方法的调用而递减1,因release()方法的调用而递增1。计数器的值永远不会小于零;当acquire()方法发现计数器为零时,将会阻塞,直到其它线程调用release()方法。
    
    定时器对象Timer:t=threading.Timer(time, function, args=None, kwargs=None),在经过time秒的间隔时间后,将会用参数args和关键字参数kwargs调用function,默认为None则使用一个空列表和空字典
    
    线程队列queue模块:
    q=queue.Queue(maxsize=0)FIFO队列的构造函数,maxsize是一个整数(默认为0),用于设置可以放入队列的项目数量的上线。一旦达到此大小,插入将阻塞,直到队列项被消耗。如果maxsize小于等于0,则队列为无限大
    q.put(item, block=True, timeout=None)将 item 放入队列。如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。
    q.get(block=True, timeout=None)从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。
    q.put_nowait(item)相当于put(item,False)
    q.get_nowait()相当于get(False)
    q.qsize()返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞
    q.empty()如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞
    q.full()如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞
    q.task_done()表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。如果被调用的次数多于放入队列中的项目数量,将引发 ValueError 异常
    q.join()阻塞至队列中所有的元素都被接收和处理完毕。当条目添加到队列的时候,未完成任务的计数就会增加。每当消费者线程调用 task_done() 表示这个条目已经被回收,该条目所有工作已经完成,未完成计数就会减少。当未完成计数降到零的时候, join() 阻塞被解除'''
    
     
    while True: print('studying...')
  • 相关阅读:
    拟真世界精密驾驶挑战 《微软飞行模拟》新截图放出
    抖音“统治”美国年轻人
    Google Play商店为预注册的游戏和应用提供自动安装功能
    小米Note 10 Lite海外发布 无缘中国市场
    亚马逊允许数万名员工在家工作直到10月2日
    刷新 翻看 我 关注 实时 疫情 何时彻底“解封”?王辰院士:北京防疫未到松懈时
    “胡汉三”饰演者刘江今晨去世,享年95岁
    虎牙年报披露2019年扭亏为盈,腾讯操持下与斗鱼合并倒计时?
    微软宣布一批新获得Microsoft Teams认证的会议硬件
    美版健康码要来了!苹果Google被网友质疑:这是变相的监视系统吗?
  • 原文地址:https://www.cnblogs.com/xuewei95/p/14862198.html
Copyright © 2011-2022 走看看