python异步队列queue验证demo

由于在做websocket接收行情的事情,估计事情做多了,python在短时间内反应不过来,考虑将数据交到别处处理,搜索后发现python有一个queue.Queue()是一个不错的工具。
主要用到三个功能,

1 queue.Queue()

可以设置一个默认大小,超过后会阻塞

2 put()

向队列中放入数据,若超过队列大小后会一直阻塞,当然,还有一个超时功能,暂时不需要。

3 get()

从队列中取数据,取到最后取空了,同样会阻塞。

然后借用一个异步任务
from apscheduler.schedulers.background import BackgroundScheduler
来进行不同任务的模拟
首先我们定义一个生产消费类:

class ProducerConsumer:
    def __init__(self, word):
        self.my_queue = queue.Queue(3)
        self.word = word

规定队列长度为3

生产数据比较简单:

    def produce(self, count):
        input_data = "{}-{}".format(self.word, count)
        self.my_queue.put(input_data)
        logger.info("put data: {}".format(input_data))

消费数据也比较简单:

    def consume(self):
        text = self.my_queue.get()
        logger.info("get data: {}".format(text))

然后就是连续的生产和消费任务:

    def batch_produce(self):
        count = 0
        while True:
            count += 1
            self.produce(count)

    def batch_consume(self):
        while True:
            self.consume()
            time.sleep(1)

生产任务不停生产数据,直到队列满了,然后被阻在那里,消费任务不停消费,为了控制节奏,每消费一个休息一秒,主要是用来观察消费不完后,生产者是否真被塞在那儿了。
然后将这两个批量任务放置到异步任务中,让他们各自运行:

    @staticmethod
    def job(obj):
        sched = BackgroundScheduler()
        sched.add_job(obj.batch_consume)
        sched.add_job(obj.batch_produce)
        sched.start()

为了使程序有趣,我们同时跑两个消费者和两个生产者,确认各自的队列不受干扰:

def do_work():
    ProducerConsumer.job(ProducerConsumer("aaaa"))
    ProducerConsumer.job(ProducerConsumer("bbbb"))
    while True:
        time.sleep(1)

运行后的数据大致如下:

[2020-04-09 15:55:58.741999][INFO][queue_demo.py][produce][23] put data: aaaa-1
[2020-04-09 15:55:58.741999][INFO][queue_demo.py][produce][23] put data: bbbb-1
[2020-04-09 15:55:58.741999][INFO][queue_demo.py][consume][38] get data: aaaa-1
[2020-04-09 15:55:58.741999][INFO][queue_demo.py][consume][38] get data: bbbb-1
[2020-04-09 15:55:58.741999][INFO][queue_demo.py][produce][23] put data: aaaa-2
[2020-04-09 15:55:58.741999][INFO][queue_demo.py][produce][23] put data: bbbb-2
[2020-04-09 15:55:58.743002][INFO][queue_demo.py][produce][23] put data: aaaa-3
[2020-04-09 15:55:58.743002][INFO][queue_demo.py][produce][23] put data: bbbb-3
[2020-04-09 15:55:58.743002][INFO][queue_demo.py][produce][23] put data: aaaa-4
[2020-04-09 15:55:58.743002][INFO][queue_demo.py][produce][23] put data: bbbb-4
[2020-04-09 15:55:59.743940][INFO][queue_demo.py][consume][38] get data: aaaa-2
[2020-04-09 15:55:59.743940][INFO][queue_demo.py][consume][38] get data: bbbb-2
[2020-04-09 15:55:59.743940][INFO][queue_demo.py][produce][23] put data: aaaa-5
[2020-04-09 15:55:59.743940][INFO][queue_demo.py][produce][23] put data: bbbb-5
[2020-04-09 15:56:00.745094][INFO][queue_demo.py][consume][38] get data: aaaa-3
[2020-04-09 15:56:00.745094][INFO][queue_demo.py][consume][38] get data: bbbb-3
[2020-04-09 15:56:00.745094][INFO][queue_demo.py][produce][23] put data: aaaa-6
[2020-04-09 15:56:00.745094][INFO][queue_demo.py][produce][23] put data: bbbb-6

很明显,由于生产中间没有停顿,所以总是尽可能生产满了,然后等消费取数据,当发现又可以生产时,立即生产,使得队列在运行时尽可能是满的状态。

最后附所有代码:

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
一个多任务下,异步queue的测试
测试生产者和消费者模型,为后面程序解耦作准备
"""
from apscheduler.schedulers.background import BackgroundScheduler
import queue
import time
import sys
sys.path.append("../../")
from utils.user_logbook import user_log as logger


class ProducerConsumer:
    def __init__(self, word):
        self.my_queue = queue.Queue(3)
        self.word = word

    def produce(self, count):
        input_data = "{}-{}".format(self.word, count)
        self.my_queue.put(input_data)
        logger.info("put data: {}".format(input_data))

    def batch_produce(self):
        count = 0
        while True:
            count += 1
            self.produce(count)

    def batch_consume(self):
        while True:
            self.consume()
            time.sleep(1)

    def consume(self):
        text = self.my_queue.get()
        logger.info("get data: {}".format(text))

    @staticmethod
    def job(obj):
        sched = BackgroundScheduler()
        sched.add_job(obj.batch_consume)
        sched.add_job(obj.batch_produce)
        sched.start()


def do_work():
    ProducerConsumer.job(ProducerConsumer("aaaa"))
    ProducerConsumer.job(ProducerConsumer("bbbb"))
    while True:
        time.sleep(1)


if __name__ == "__main__":
    do_work()

日志采用logbook的日志封装,在此一并附上:

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# filename:user_logbook.py
import os
import logbook
from logbook import Logger, TimedRotatingFileHandler
from logbook.more import ColorizedStderrHandler
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.00"


def user_handler_log_formatter(record, handler):
    log = "[{dt}][{level}][{filename}][{func_name}][{lineno}] {msg}".format(
        dt=record.time,
        level=record.level_name,                        # 日志等级
        filename = os.path.split(record.filename)[-1],  # 文件名
        func_name = record.func_name,                   # 函数名
        lineno = record.lineno,                         # 行号
        msg=record.message,                             # 日志内容
    )
    return log


# 打印到屏幕句柄
user_std_handler = ColorizedStderrHandler(bubble=True)
user_std_handler.formatter = user_handler_log_formatter
# 日志路径,在主工程下生成log目录
LOG_DIR = os.path.join('../log')
if not os.path.exists(LOG_DIR):  
    os.makedirs(LOG_DIR)
    
# 打印到文件句柄
user_file_handler = TimedRotatingFileHandler(
    os.path.join(LOG_DIR , '%s.log' % 'server'), date_format='%Y%m%d', bubble=True)
user_file_handler.formatter = user_handler_log_formatter


# 用户代码logger日志
user_log = Logger("user_log")


def init_logger():
    logbook.set_datetime_format("local")
    user_log.handlers = []
    user_log.handlers.append(user_std_handler)
    user_log.handlers.append(user_file_handler)    


# 初始化日志系统(被默认调用)
init_logger()
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永远的麦田

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值