手写单向队列性能秒杀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

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

黑神话,XSKY 星飞全闪单卷性能突破310万

当下,云计算仍然是企业主要的基础架构,随着关键业务的逐步虚拟化和云化,对于块存储的性能要求也日益提高。企业对于低延迟、高稳定性的存储解决方案的需求日益迫切。为了满足这些日益增长的 IO 密集型应用场景,众多云服务提供商正在不断推陈出新,推出具有更低时延和更高 IOPS 性能的云硬盘产品。 8 月 22 日 2024 DTCC 大会上(第十五届中国数据库技术大会),XSKY星辰天合正式公布了基于星

4B参数秒杀GPT-3.5:MiniCPM 3.0惊艳登场!

​ 面壁智能 在 AI 的世界里,总有那么几个时刻让人惊叹不已。面壁智能推出的 MiniCPM 3.0,这个仅有4B参数的"小钢炮",正在以惊人的实力挑战着 GPT-3.5 这个曾经的AI巨人。 MiniCPM 3.0 MiniCPM 3.0 MiniCPM 3.0 目前的主要功能有: 长上下文功能:原生支持 32k 上下文长度,性能完美。我们引入了

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用