python 消息队列

本文介绍了Python中使用multiprocessing模块实现消息队列的方式,包括Queue和Pipe。详细讲解了Queue对象的成员函数,如put、get、qsize等,并提到了Celery作为异步分布式任务调度模块在消息队列中的应用,以及如何配置和启动Celery worker。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消息队列”是在消息的传输过程中保存消息的容器。
消息队列最经典的用法就是消费者和生成者之间通过消息管道来传递消息,消费者和生成者是不通的进程。生产者往管道中写消息,消费者从管道中读消息。
操作系统提供了很多机制来实现进程间的通信 ,multiprocessing模块就提供了Queue和Pipe两种方法来实现。

使用multiprocessing里面的Queue来实现消息队列

复制代码
from multiprocessing import Queue, Process

#写进程
def write(q):
    for i in ["a","b","c","d"]:
         q.put(i)
         print("put {0} to queue".format(i))
#读进程
def read(q):
    while 1:
        result = q.get()
        print("get {0} from queue".format(result))
#主函数
def main():
# 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write,args=(q,))
    pr = Process(target=read,args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pe,读入:
    pr.start()
   # 等待pw结束:
    pw.join()
  # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

if __name__ == "__main__":
    main()
结果

put a to queue

get a from queue
put b to queue

get b from queue

put c to queue

get c from queue

put d to queue
get d from queue

复制代码 

通过Mutiprocess里面的Pipe来实现消息队列:
1, Pipe方法返回(conn1, conn2)代表一个管道的两个端。Pipe方法有duplex参数,如果duplex参数为True(默认值),那么这个管道是全双工模式,也就是说conn1和conn2均可收发。duplex为False,conn1只负责接受消息,conn2只负责发送消息。
2, send和recv方法分别是发送和接受消息的方法。close方法表示关闭管道,当消息接受结束以后,关闭管道。

复制代码
from multiprocessing import Pipe,Process

import time

def proc1(pipe):
    for i in xrange(1,10):
        pipe.send(i)
        print("send {0} to pipe".format(i))
        time.sleep(1)
def proc2(pipe):
    n = 9
    while n >0:
        result = pipe.recv()
        print("recv {0} from pipe".format(result))
        n -= 1

def main():
    pipe = Pipe(duplex=False)
    print(type(pipe))
    p1 = Process(target=proc1,args=(pipe[1],))
    p2 = Process(target=proc2,args=(pipe[0],))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    pipe[0].close()
    pipe[1].close()

if __name__ == '__main__':
    main()


输出结果:
<type 'tuple'>
send 1 to pipe
recv 1 from pipe
recv 2 from pipe
send 2 to pipe
send 3 to pipe
recv 3 from pipe
send 4 to pipe
recv 4 from pipe
send 5 to piperecv 5 from pipe

recv 6 from pipe
send 6 to pipe
recv 7 from pipe
send 7 to pipe
recv 8 from pipe
send 8 to pipe
recv 9 from pipe
send 9 to pipe
复制代码

Python提供了Queue模块来专门实现消息队列Queue对象
Queue对象实现一个fifo队列(其他的还有lifo、priority队列,这里不再介绍)。queue只有maxsize一个构造参数,用来指定队列容量,指定为0的时候代表容量无限。主要有以下成员函数:
Queue.qsize():返回消息队列的当前空间。返回的值不一定可靠。
Queue.empty():判断消息队列是否为空,返回True或False。同样不可靠。
Queue.full():类似上边,判断消息队列是否满
Queue.put(item, block=True, timeout=None):往消息队列中存放消息。block可以控制是否阻塞,timeout指定阻塞时候的等待时间。如果不阻塞或者超时,会引起一个full exception。
Queue.put_nowait(item):相当于put(item, False).
Queue.get(block=True, timeout=None):获取一个消息,其他同put。

以下两个函数用来判断消息对应的任务是否完成。
Queue.task_done():接受消息的线程通过调用这个函数来说明消息对应的任务已完成。
Queue.join(): 实际上意味着等到队列为空,再执行别的操作

 

例子:

复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @time: 2017/12/18 19:31
# Author: caicai
# @File: demon3.py

'''写一个消费者和生产者,为了练习多线程,用多线程的方式实现,并通过类的重写的方法来实现'''
from Queue import Queue
from threading import Thread
import time

#生成类,输出一堆数字
class Proceduer(Thread):
    def __init__(self,queue):
        super(Proceduer, self).__init__()
        self.queue = queue
    def run(self):
        try:
            for i in xrange(1,10):
                print("put data is: {0} to queue".format(i))
                self.queue.put(i)

        except Exception as e:
            print("put data error!")
            raise e

#消费者类
class Consumer_odd(Thread):
    def __init__(self,queue):
        super(Consumer_odd, self).__init__()
        self.queue = queue
    def run(self):
        try:
            while not self.queue.empty():
                number = self.queue.get()
                if number % 2 != 0:
                    print("get {0} from queue ODD".format(number))
                else:
                    self.queue.put(number)
                time.sleep(1)
        except Exception as e:
            raise e

class Consumer_even(Thread):
    def __init__(self,queue):
        super(Consumer_even, self).__init__()
        self.queue = queue
    def run(self):
        try:
            while not self.queue.empty(): #queue.empty() 
                number = self.queue.get()
                if number % 2 == 0:
                    print("get {0} from queue EVEN,thread name is: {1}".format(number, self.getName()))
                else:
                    self.queue.put(number)
                time.sleep(1)
        except Exception as e:
            raise e

def main():
    queue = Queue()

    p = Proceduer(queue=queue)
    p.start()
    p.join()
    time.sleep(1)
    c1 = Consumer_odd(queue=queue)
    c2 = Consumer_even(queue=queue)
    c1.start()
    c2.start()
    c1.join()
    c2.join()

    print("All threads terminate!")

if __name__ == '__main__':
    main()

输出结果:

put data is: 1 to queue
put data is: 2 to queue
put data is: 3 to queue
put data is: 4 to queue
put data is: 5 to queue
put data is: 6 to queue
put data is: 7 to queue
put data is: 8 to queue
put data is: 9 to queue
get 1 from queue ODD
get 2 from queue EVEN,thread name is: Thread-3
get 5 from queue ODD
get 6 from queue EVEN,thread name is: Thread-3
get 7 from queue ODD
get 8 from queue EVEN,thread name is: Thread-3
get 9 from queue ODD
get 4 from queue EVEN,thread name is: Thread-3get 3 from queue ODD

All threads terminate!
复制代码

celery异步分布式
Celery是一个python开发的异步分布式任务调度模块。
Celery本身并不提供消息服务,使用第三方服务,也就是borker来传递任务,目前支持rebbimq,redis, 数据库等。

这里我们使用redis
连接url的格式为:
redis://:password@hostname:port/db_number
例如:
BROKER_URL = 'redis://localhost:6379/0'

 

 

安装celery
pip install celery
pip install redis

 

在服务器上安装redis服务器,并启动redis
第一个简单的例子:

复制代码
[root@localhost celery]# cat test.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
from celery import Celery

broker = "redis://10.37.208.40:6379/5"
backend = "redis://10.37.208.40:6379/6"
app = Celery("test",broker=broker,backend=backend)

@app.task
def add(x,y):
    return x+y
 
复制代码

启动worker
#celery -A ling worker -l info


生产者

复制代码
启动worker
#celery -A test worker -l info


生产者

form test import add
a = add.delay(10, 20)
print(a.result)    #获取结果
print(a.ready)        #是否处理
print(a.get(timeout=1))        #获取结果
print(a.status)        #是否处理



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值