c++基础组件性能对比测试(1)双向队列std::deque和libuv队列

本文通过实验对比了libuv队列和C++标准库std::deque在不同场景下的性能表现,包括对象生成、队列插入及弹出等操作。

 

libuv中提供了一组宏,非常的简短,并且在放在了queue.h中,直接拷贝过来引用就可以对普通的类连接成一个队列,这里对比一下QUEUE和标准库中的std::deque的性能差别:

有如下几种解决方案:

1)libuv链接基础结构体或者类,自己管理了内存和指针,

2)std::deque存储对象实例,不需要关心内存

3)std::deque存储裸指针,需要自己释放内存

4)std::deque存储智能指针,不需要关心释放

5)std::deque存储半智能对象(继承enable_shared_from_this)

第一组测试:对比生成裸指针的简单对象以及智能指针对象的效率,发现差别比较大:

测试结果如下:

生成方法10000个对象耗时(ms)速度对比
简单对象9最快
智能指针17.51.7倍时间
智能对象222.2倍时间

 

代码如下:其中计时的类请参考我以前 的文章

struct Student {
	Student(int a, const char * s) :age(a), name(s)
	{
	}

	Student() = default;
	QUEUE node;
	int age;
	std::string name;
	
};

class StudentAuto : public enable_shared_from_this<StudentAuto>
{
public:
	StudentAuto(int a, const char * s) :age(a), name(s)
	{
	}

	StudentAuto() = default;

	std::shared_ptr<StudentAuto> getptr() {
		return shared_from_this();
	}

	~StudentAuto()
	{
		//std::cout << "析构StudentAuto" << endl;
	}
	QUEUE node;
	int age;
	std::string name;

};

void test5()
{
	Timer timer1;
	timer1.start();

	// 内存泄露
	Student * it = nullptr;
	for (int i = 0; i < 10000; i++)
	{
		it = new Student(i+1, "robin");
	}

	auto duration1 = timer1.stop_delta<std::milli>();
	std::cout << "生成10000 简单实体(ms): " << duration1 << endl;

	timer1.start();

	std::shared_ptr<Student> ptr[10000];
	for (int i = 0; i < 10000; i++)
	{
		ptr[i] =  make_shared<Student>(i + 1, "robin");
		//std::shared_ptr<Student> it = make_shared<Student>(i + 1, "robin");
	}

	auto duration2 = timer1.stop_delta<std::milli>();
	std::cout << "生成10000 智能实体(ms): " << duration2 << endl;
}

 

第二组对比:将各种对象插入2种队列测试

结果如下:

执行方法10000个操作耗时(ms)结论
已有简单对象插入UV队列0.045快,忽略不计
已有简单对象头部弹出UV队列0.0611快,忽略不计
生成简单对象插入UV队列9耗时在生成对象
   
std::deque指针尾部插入裸指针7.5 
std::deque头部弹出裸指针7.4 
std::deque尾部emplace_back简单对象19 
std::deque头部弹出简单对象14 
std::deque尾部生成并插入智能指针24不如直接插入对象

结论:

1)高并发服务器可以考虑使用LIBUV的队列管理,自己使用内存池来管理内存块;

2)普通的应用可以考虑使用std::deque直接管理对象,比插智能指针块

代码大概如下:


// 系统忙
//插入UV队列(ms):0.1168
//头部弹出(ms): 0.1078
//插入std::deque(ms): 20.5516
//弹出std::deque(ms): 32.1022

// 空闲
//插入UV队列(ms):0.045
//头部弹出(ms): 0.0611
//插入std::deque(ms): 7.4969
//弹出std::deque(ms): 7.3878
void test1()
{
	Student * students = new Student[10000];
	Student * it = students;
	for (int i = 0; i < 10000; i++)
	{
		it = students + i;
		it->age = i + 1;
		it->name = "robin";
	}

	Timer timer1;
	timer1.start();

	// 在UV插入信息
	QUEUE queue;
	QUEUE_INIT(&queue);

	for (int i = 0; i < 10000; i++)
	{
		it = students + i;

		QUEUE_INIT(&(it->node));
		QUEUE_INSERT_TAIL(&queue, &(it->node));
	}



	auto duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入UV队列(ms):" << duration1 << endl;

	// 头部弹出
	QUEUE *p;
	timer1.start();
	for (int i = 0; i < 10000; i++)
	{
		p = QUEUE_HEAD(&queue);
		if (p != &queue)
		{
			QUEUE_REMOVE(p);
		}
	}
	duration1 = timer1.stop_delta<std::milli>();
	std::cout << "头部弹出(ms): " << duration1 << endl;

	// 测试std::deque
	timer1.start();
	std::deque<Student *> studentQue;

	for (int i = 0; i < 10000; i++)
	{
		it = students + i;
		studentQue.push_back(it);
	}

	duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入std::deque (ms): " << duration1 << endl;

	timer1.start();
	for (int i = 0; i < 10000; i++)
	{
		studentQue.pop_front();
	}
	duration1 = timer1.stop_delta<std::milli>();
	std::cout << "弹出std::deque (ms): " << duration1 << endl;

	// 取出头测试
	/*QUEUE *p;
	p = QUEUE_HEAD(&queue);
	p = QUEUE_NEXT(p);
	Student *first_stu = QUEUE_DATA(p, struct Student, node);*/

	/**
	* Should output the name of wesley.
	*/
	/*printf("Received first inserted Student: %s who is %d.\n",
		first_stu->name.c_str(), first_stu->age);
*/
/*QUEUE_FOREACH(p, &queue) {
	Student *tmp = QUEUE_DATA(p, struct Student, node);
	cout << "name: " << tmp->name << " age: " << tmp->age << endl;

}*/

	delete[] students;
}
// 系统忙
//插入UV队列(ms):17.3848
//插入std::deque(ms): 50.7232
//弹出std::deque(ms): 46.7094

// 系统空闲
//插入UV队列(ms):9.0955
//插入std::deque(ms): 19.8008
//弹出std::deque(ms): 14.6486
void test2()
{

	// 在UV插入信息

	Timer timer1;
	timer1.start();

	Student * students = new Student[10000];
	Student * it = students;
	for (int i = 0; i < 10000; i++)
	{
		it = students + i;
		it->age = i + 1;
		it->name = "robin";
	}
	QUEUE queue;
	QUEUE_INIT(&queue);

	for (int i = 0; i < 10000; i++)
	{
		it = students + i;

		QUEUE_INIT(&(it->node));
		QUEUE_INSERT_TAIL(&queue, &(it->node));
	}

	auto duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入UV队列(ms):" << duration1 << endl;
	/////////////////////////////////////////////////////////
	timer1.start();
	std::deque<Student> studentQue;
	for (int i = 0; i < 10000; i++)
	{
		studentQue.emplace_back(i+1, "robin");
	}

	duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入std::deque (ms): " << duration1 << endl;

	timer1.start();
	for (int i = 0; i < 10000; i++)
	{
		//cout << studentQue[0].age << endl;
		studentQue.pop_front();
	}
	duration1 = timer1.stop_delta<std::milli>();
	std::cout << "弹出std::deque (ms): " << duration1 << endl;

	delete[] students;
}

//插入10000std::deque智能指针(ms): 64.094
//插入10000std::deque对象(ms): 55.6962
using StudentPtr = std::shared_ptr<Student>;
void test3()
{

	Timer timer1;
	timer1.start();
	
	std::deque<StudentPtr> studentQ;
	for (int i = 0; i < 10000; i++)
	{
		studentQ.push_back(std::make_shared<Student>(i + 1, "robin"));
	}
	auto duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入10000std::deque智能指针 (ms): " << duration1 << endl;

	timer1.start();
	std::deque<Student> studentQue;
	for (int i = 0; i < 10000; i++)
	{
		studentQue.emplace_back(i + 1, "robin");
	}

	duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入10000std::deque对象(ms): " << duration1 << endl;

}

void test4()
{
	// 在UV插入信息

	Timer timer1;
	timer1.start();

	QUEUE queue;
	QUEUE_INIT(&queue);

	for (int i = 0; i < 10000; i++)
	{
		std::shared_ptr<StudentAuto> it = make_shared<StudentAuto>(i + 1, "robin");

		QUEUE_INIT(&(it->node));
		QUEUE_INSERT_TAIL(&queue, &(it->node));
	}

	auto duration1 = timer1.stop_delta<std::milli>();
	std::cout << "插入10000智能对象UV队列(ms):" << duration1 << endl;
}

 

 

<think>首先,用户的问题是:“static std::deque std::deque的区别”,这看起来像是关于C++std::deque的。问题是关于“static std::deque普通的“std::deque”的区别。在C++中,“static”通常是一个关键字,用于指定存储持续时间。 回想一下C++的关键字: - “static”在变量声明中表示变量具有静态存储持续时间,意味着它在程序的整个生命周期中持续存在。 - “std::deque”是标准模板中的一个容器,表示双端队列。 可能的误解: - 用户可能在问声明为静态的std::deque对象与普通std::deque对象的区别。 - 或者,用户可能打错了,比如可能是“std::deque” vs “std::queue”,但问题明确是“static std::deque” vs “std::deque”。 分析问题: - “std::deque”是一个类型,是一个动态数组,允许在两端高效插入删除。 - “static std::deque”可能指的是一个静态实例的std::deque。 在C++中: - 如果你声明一个变量为static,例如:`static std::deque<int> myDeque;` - 这是一个静态变量,它在函数外部或函数内部声明时具有静态存储持续时间。 - 与之相对的是自动存储持续时间,例如:`std::deque<int> myDeque;` 在函数内部声明时。 所以,区别在于存储持续时间作用域: 1. **存储持续时间**: - 静态std::deque:在程序启动时初始化,在程序结束时销毁。内存在整个程序运行期间存在。 - 普通std::deque(自动):在进入作用域时初始化,在离开作用域时销毁。内存只在作用域内有效。 2. **作用域**: - 如果声明在全局或命名空间作用域,`static`可能用于内部链接(在C++17之前),但C++17引入了内联变量,跨文件共享。 - 在函数内部,`static`变量只在第一次进入函数时初始化,之后保留值。 3. **行为**: - 静态变量的值在多次调用之间保持持久。 - 自动变量每次进入作用域时重新初始化。 因此,回答应该澄清这个区别。 现在,关于输出格式: - 我必须使用中文回答问题。 - 在回答完问题后,必须提出3-5个相关问题。 - 相关问题必须以“§§相关问题§§”开头,并在同一行输出。 - 然后,列出1. 2. 3. ... 每个问题占一行。 - 禁止换行分散,意思是相关问题部分应该连续输出,没有额外的换行。 示例格式给出了一个代码块,但用户的问题没有代码,所以我可能不需要代码块。用户的问题是纯文本的。 结构化我的回答: 1. 先解释区别。 2. 然后输出相关问题。 确保回答在中文。 草拟回答: - 解释:static std::deque 指的是一个具有静态存储持续时间的 std::deque 对象。而 std::deque 通常指的是一个具有自动存储持续时间的对象(如果在局部作用域声明)。主要区别在于生命周期作用域。 - 静态变量在整个程序生命周期存在。 - 自动变量在作用域退出时销毁。 - 例如,在函数中:static std::deque<int> sd; 会保持状态跨调用;而 std::deque<int> ad; 每次调用重新创建。 相关问题:基于这个主题,提出3-5个相关问题。 - 例如: 1. 静态变量在C++中如何影响内存管理? 2. std::dequestd::vector的主要区别是什么? 3. 使用静态容器有哪些潜在问题? 4. 如何在多线程环境下安全使用静态std::deque? 5. 还有其他存储持续时间如thread_local vs static的区别? 确保相关问题是基于用户的问题相关主题。 完整响应: - 先用中文回答问题。 - 然后以“§§相关问题§§”开头。 - 列出相关问题编号1. 2. 3. ... 最终回答: </think>在C++中,“static std::dequestd::deque”的主要区别在于对象的**存储持续时间****生命周期**,这会影响内存管理、作用域程序行为。以下是核心区别: - **static std::deque**: - 当使用`static`关键字声明时(如`static std::deque<int> myDeque;`),该对象具有**静态存储持续时间**。 - **生命周期**:在程序启动时初始化(首次遇到声明时),在程序结束时销毁。这意味着对象的内存数据在整个程序运行期间持久存在。 - **作用域**:如果在函数内部声明,它只在声明的作用域可见,但其值在多次函数调用之间保持不变(状态持久)。如果在全局或命名空间作用域声明,`static`可能影响链接性(C++17前用于内部链接)。 - **使用场景**:适用于需要跨函数调用保留状态的场景,如缓存或全局数据存储,但需注意线程安全。 - **std::deque**(普通声明): - 不添加`static`时(如`std::deque<int> myDeque;`),对象默认具有**自动存储持续时间**(如果在函数或局部块内声明)。 - **生命周期**:在进入声明的作用域时初始化,在离开作用域时销毁。每次进入作用域时重新创建,数据不持久。 - **作用域**:仅限于声明的作用域(如函数内部),外部无法访问。销毁后内存回收。 - **使用场景**:适用于临时数据操作,如函数内部的临时容器,避免内存泄漏风险。 **关键区别总结**: - **持久性**:静态版本保留数据跨作用域,普通版本每次作用域退出时重置。 - **内存占用**:静态对象可能增加程序内存占用,普通对象在作用域结束后释放内存。 - **初始化**:静态对象只初始化一次,普通对象每次声明时初始化。 - **线程安全**:静态对象在多线程环境中需同步机制(如mutex),普通对象通常更安全(限于局部)。 例如: ```cpp void example() { static std::deque<int> staticDeque; // 静态: 跨调用保存数据 std::deque<int> autoDeque; // 自动: 每次调用重新创建 staticDeque.push_back(1); // 后续调用会累积元素 autoDeque.push_back(1); // 每次调用后销毁 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值