手写单向队列性能秒杀std::queue

2024-06-18 05:32

本文主要是介绍手写单向队列性能秒杀std::queue,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

std::queue即单向队列,是一种先入先出的FIFO队列。具有以下特点:

  • 只允许从队尾插入元素,从队头删除元素
  • 先进先出(First In First Out)
  • 不允许在中间部位进行操作

一共6个函数front()、back()、push()、pop()、empty()、size(),自己手写实现,也是比较简单的。

接下来, 我们就手写实现一个定制的queue队列,然后将其与std::queue性能进行对比。

一、IORequestQueue队列类实现

IORequestQueue.h

#ifndef IOREQUESTQUEUE_H
#define IOREQUESTQUEUE_H#include <assert.h>struct IORequest
{IORequest* p;int data;int ioType;unsigned int requestIndex;
};class IORequestQueue
{
public:IORequestQueue(): pHead(nullptr),pTail(nullptr),count(0){}// 队列是否为空bool empty() const{return (pHead == nullptr);}// 返回队列中元素个数size_t size() const{return count;}// 返回队头元素IORequest* front(){assert(!empty());return pHead;}// 返回队尾元素IORequest* back(){assert(!empty());return pTail;}// 将变量request从队列尾入队void push(IORequest* request){request->p = nullptr;if (pHead == nullptr){assert(pTail == nullptr);pHead = request;}else{assert(pTail != nullptr);pTail->p = request;}pTail = request;count++;}// 将队头元素弹出void pop(){assert(!empty());pHead = pHead->p;if (pHead == nullptr){pTail = nullptr;}count--;}private:IORequest* pHead;IORequest* pTail;size_t count;
};#endif // IOREQUESTQUEUE_H

struct IORequest结构体是需要加入到队列中的元素类型,其中IORequest* p为指向下一个元素的指针,其余均为测试成员变量。

IORequestQueue类是队列实现,分别参考std::queue实现了6个函数,基本原理是记录首尾元素的地址,其间各元素之间依靠IORequest* p进行连接。

二、IORequestQueue与std::queue性能对比

对IORequestQueue与std::queue进行测试,main.cpp如下:

#include <QCoreApplication>
#include <queue>
#include <QDebug>
#include "IORequestQueue.h"
#include "CTimer.h"void testStdQueue(std::vector<IORequest>& requests)
{/***********************测试入队*************************/CTimer timer;timer.reset();std::queue<IORequest*> stdQueue;for (unsigned int i = 0; i < requests.size(); i++) // 将IO请求添加到std::queue队列中{stdQueue.push(&requests[i]);}double elapsed = timer.end();qDebug() << "std::queue push:" << elapsed << "us";/***********************测试出队*************************/timer.reset();for (unsigned int i = 0; i < requests.size(); i++) // 从std::queue出队列{IORequest* req = stdQueue.front(); // 返回队头元素stdQueue.pop(); // 将队头元素弹出}elapsed = timer.end();qDebug() << "std::queue pop:" << elapsed << "us";
}void testIOQueue(std::vector<IORequest>& requests)
{/***********************测试入队*************************/CTimer timer;timer.reset();IORequestQueue ioQueue;for (unsigned int i = 0; i < requests.size(); i++) // 将IO请求添加到IORequestQueue队列中{ioQueue.push(&requests[i]);}double elapsed = timer.end();qDebug() << "IORequestQueue push:" << elapsed << "us";/***********************测试出队*************************/timer.reset();for (unsigned int i = 0; i < requests.size(); i++) // 从IORequestQueue出队列{IORequest* req = ioQueue.front(); // 返回队头元素ioQueue.pop(); // 将队头元素弹出}elapsed = timer.end();qDebug() << "IORequestQueue pop:" << elapsed << "us";
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 准备测试元素10000个std::vector<IORequest> requests;for (unsigned int index = 0; index < 10000; index++){IORequest req;req.data = 0;req.ioType = 0;req.requestIndex = index;requests.push_back(req);}testStdQueue(requests); // 测试std::queuetestIOQueue(requests);  // 测试IORequestQueuereturn a.exec();
}

程序中分别对10000个元素,使用std::queue进行入队和出队,使用IORequestQueue进行入队和出队,并记录每个步骤消耗的时间。

运行结果:

在这里插入图片描述

可以看到同样入队10000个元素时:

  • std::queue消耗173062 us
  • IORequestQueue消耗499.2 us

IORequestQueue性能比std::queue提升99.7%

同样出队10000个元素时:

  • std::queue消耗2338 us
  • IORequestQueue消耗274.9 us

IORequestQueue性能比std::queue提升88.2%

然而,这还只是MSVC编译器,debug版本下的测试结果,release下提升更多。

三、总结

std::queue由于使用模板,适用于各种类型,另外其底下使用deque(double-ended queue,双端队列)实现,可能在性能上,有一些下降。

在性能和类型通用性上有一些兼顾,故而导致性能不及为某一特定类型元素定制的queue,也可以理解。

建议:

  • 在频繁入队、出队的场合下,尽量使用自己手写实现的queue,这样性能损失较少,并在业务代码中,尽量复用元素对象,避免频繁申请和释放内存。可参考IORequestQueue实现,比较简单。

  • 在非频繁入队、出队的场合下,使用std::queue,适用于各种类型,代码实现更方便。



若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!

同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。

本文涉及工程代码,公众号回复:20Queue,即可下载。

在这里插入图片描述

这篇关于手写单向队列性能秒杀std::queue的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071428

相关文章

19.手写Spring AOP

1.Spring AOP顶层设计 2.Spring AOP执行流程 下面是代码实现 3.在 application.properties中增加如下自定义配置: #托管的类扫描包路径#scanPackage=com.gupaoedu.vip.demotemplateRoot=layouts#切面表达式expression#pointCut=public .* com.gupaoedu

17.用300行代码手写初体验Spring V1.0版本

1.1.课程目标 1、了解看源码最有效的方式,先猜测后验证,不要一开始就去调试代码。 2、浓缩就是精华,用 300行最简洁的代码 提炼Spring的基本设计思想。 3、掌握Spring框架的基本脉络。 1.2.内容定位 1、 具有1年以上的SpringMVC使用经验。 2、 希望深入了解Spring源码的人群,对 Spring有一个整体的宏观感受。 3、 全程手写实现SpringM

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。 面试官:那你知道STL中的stack是如何实现的吗? 二师兄:默认情况下,stack使

Java中如何优化数据库查询性能?

Java中如何优化数据库查询性能? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨在Java中如何优化数据库查询性能,这是提升应用程序响应速度和用户体验的关键技术。 优化数据库查询性能的重要性 在现代应用开发中,数据库查询是最常见的操作之一。随着数据量的增加和业务复杂度的提升,数据库查询的性能优化显得尤为重

神经网络第四篇:推理处理之手写数字识别

到目前为止,我们已经介绍完了神经网络的基本结构,现在用一个图像识别示例对前面的知识作整体的总结。本专题知识点如下: MNIST数据集图像数据转图像神经网络的推理处理批处理  MNIST数据集          mnist数据图像 MNIST数据集由0到9的数字图像构成。像素取值在0到255之间。每个图像数据都相应地标有“7”、“2”、“1”等数字标签。MNIST数据集中,

【数据结构与算法 经典例题】使用队列实现栈(图文详解)

💓 博客主页:倔强的石头的CSDN主页               📝Gitee主页:倔强的石头的gitee主页    ⏩ 文章专栏:《数据结构与算法 经典例题》C语言                                   期待您的关注 ​​ 目录  一、问题描述 二、前置知识 三、解题思路 四、C语言实现代码 🍃队列实现代码:

Clickhouse 的性能优化实践总结

文章目录 前言性能优化的原则数据结构优化内存优化磁盘优化网络优化CPU优化查询优化数据迁移优化 前言 ClickHouse是一个性能很强的OLAP数据库,性能强是建立在专业运维之上的,需要专业运维人员依据不同的业务需求对ClickHouse进行有针对性的优化。同一批数据,在不同的业务下,查询性能可能出现两极分化。 性能优化的原则 在进行ClickHouse性能优化时,有几条

RabbitMQ实践——临时队列

临时队列是一种自动删除队列。当这个队列被创建后,如果没有消费者监听,则会一直存在,还可以不断向其发布消息。但是一旦的消费者开始监听,然后断开监听后,它就会被自动删除。 新建自动删除队列 我们创建一个名字叫queue.auto.delete的临时队列 绑定 我们直接使用默认交换器,所以不用创建新的交换器,也不用建立绑定关系。 实验 发布消息 我们在后台管理页面的默认交换器下向这个队列

Java并发编程—阻塞队列源码分析

在前面几篇文章中,我们讨论了同步容器(Hashtable、Vector),也讨论了并发容器(ConcurrentHashMap、CopyOnWriteArrayList),这些工具都为我们编写多线程程序提供了很大的方便。今天我们来讨论另外一类容器:阻塞队列。   在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了D

剑指offer—编程题7(用两个栈实现一个队列)

题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail 和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。 代码如下: [java]  view plain copy print ? public class Test07 {       /**       * 用两个栈模拟的队列       *