• 12.2、多线程通信:queue


    queue:

    • 什么是队列:是一种特殊的结构,类似于列表。不过就像排队一样,队列中的元素一旦取出,那么就会从队列中删除。
    • 线程之间的通信可以使用队列queue来进行
    • 线程如何使用queue.Queue【还有其他类型的对象下面讲】来通信:
      • 1.创建一个Queue对象:对象=queue.Queue(x),x是队列容量,x可以不填,默认没有容量限制,    
      • 2.get()可以使线程从队列中获取一个元素,如果队列为空,get会等待,get可以设置timeout参数,这是等待时间
      • 3.put()可以往队列中放入一个元素【默认队列Queue是先入先出的,先放入的元素会先取出去】,如果队列满了,put会等待,put可以设置timeout参数,这是等待时间
      • image

    【下例为:sender线程发送直径给recvder线程,recvder计算得出周长】

    import threading,time,queue,random
    def sender():#sender发送直径
        while True:
            x=random.randint(1,10)
            print("send done:",x)
            q.put(x)#每个一秒就放入一个随机数
            time.sleep(1)#每隔一秒就放入一个a
    
    def recvder():#recvder计算周长
       while True:
           x=q.get()
           print("recv done:",x*3.14)#每隔一秒就取出一个元素,计算结果
           time.sleep(1)
    
    q=queue.Queue()
    t1=threading.Thread(target=sender)
    t2=threading.Thread(target=recvder)
    
    t1.start()
    t2.start()
    
    t1.join()
    t2.join()
    • Queue 对象已经包含了必要的锁,所以不用担心会出错
    import threading,time,queue,random
    def sender():#sender发送直径
        while True:
            x=random.randint(1,10)
            print("send done:",x)
            q.put(x)#每个一秒就放入一个随机数
            time.sleep(1)#每隔一秒就放入一个a
    
    def recvder():#recvder计算周长
       while True:
           x=q.get()
           print(threading.current_thread(),"recv done:",x*3.14)#每隔一秒就取出一个元素,计算结果
           time.sleep(2)
    
    
    q=queue.Queue()
    t1=threading.Thread(target=sender)
    t2=threading.Thread(target=recvder)
    t3=threading.Thread(target=recvder)
    
    t1.start()
    t2.start()
    t3.start()
    
    t1.join()
    t2.join()
    t3.join()

    注:

    队列可以有容量限制:

    image

    timeout的设置:

    image


    队列的其他相关函数【设q为一个Queue对象】:

    • q.qsize():返回当前队列的元素个数
    • q.empty():判断队列是否空,返回布尔值
    • q.full():判断队列是否满,返回布尔值
    • q.get_nowait():直接使用get(),如果此时队列中没有元素,那么会阻塞等待,使用get_nowait()后,如果队列中没有元素,那么会报错
    • q.put_nowait():直接使用put(),如果此时队列满了,那么会阻塞等待,使用put_nowait()后,如果队列已经满了,那么会报错

     

    • q.task_done() :在完成一项工作之后,task_done()函数向任务已经完成的队列发送一个信号【功能类似于:有一个只能承重一个人的独木桥,A来了发现B在桥上,所以A不能上桥,他就在等,等到B过完桥后喊一下他,他才知道B过完桥了】【q.task_done主要是跟q.join()配合使用的】
    • q.join():实际上意味着等到队列为空,再执行别的操作【每次get后需要调用task_done,直到所有队列为空,这时才会执行join下面的】
    import threading,queue,time
    """
    这个例子是:厂家跟司机约定,生产满3个,司机才来拉,
    而一个个拉走,只有当3个都拉走,厂家才继续生产
    """
    def producer():#厂家
        while True:
            for i in range(3):
                q.put(i)
            start_time=time.time()
            q.join()##结果显示join这里堵塞住了厂家线程
            print("wait time:",time.time()-start_time)#用来测试是否堵塞,证明不是因为司机的sleep堵塞运行
    
    
    def driver():#老司机
        while True:
            for i in range(3):
                print(q.get())
                q.task_done()
            print("")
            time.sleep(2)
    
    
    q=queue.Queue()
    t1=threading.Thread(target=producer)
    t2=threading.Thread(target=driver)
    
    t1.start()
    t2.start()
    
    t1.join()
    t2.join()

    image


    queue中除了Queue之外,还有其他的队列,下面是常用的几个:

    • Queue是先入先出的队列:

    image

    • LifoQueue则是后入先出的队列

    image

    • PriorityQueue是由装入元素时指定的优先级来决定出元素的顺序的:
      • 创建方法:队列对象=queue.PriorityQueue()
      • 优先级是小的优先,但不能混合排序,str的只能跟str的一起排序,int的只能跟int一起排序
      • PriorityQueue的put的参数是元组,格式为:队列对象.put((优先级, 数据))

    imageimage

    • deque 是双端队列,允许先入先出和后入后出,即两端都可以出

  • 相关阅读:
    WebForm跨页面传值---内置对象
    后台获得集合,变成json字符串,放到EL表达式,js进行获取遍历
    Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚)
    DELPHI美化界面(2009开始TPanel增加了ParentBackGround)
    在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!(更好的管理异常)
    delphi中最小化其他程序及所有程序最小化(使用 shell.minimizeAll 和自己寻找窗口这两种办法)
    电脑睡眠状态(ACPI规范定义了七个状态,使用powercfg -a进行查看)
    javascript
    Master-Worker模式
    程序员的基础和解决问题的思维
  • 原文地址:https://www.cnblogs.com/progor/p/8436559.html
Copyright © 2020-2023  润新知