C++代码优化之nim_duilib控件关联

前言

  • 使用nim_duilib关联控件,优化后。的确减少了代码量,那么,执行效率呢?
  • 时间执行的长短与硬件、软件有关,以下内容仅为参考。

测试代码

  • 下面的代码,分为两部分, 循环使用for,非循环则直接使用数组索引
  • Release model执行测试结果

循环代码

ui::Button *pbtn_arr_[12] = { nullptr };
long long start = std::chrono::system_clock::now().time_since_epoch().count();

for (auto item : pbtn_arr_)
{
	find_control2(std::wstring(L"btn_blue"), item);
}

long long end = std::chrono::system_clock::now().time_since_epoch().count();
std::wstring sss =fmt::format(L"{}", (end-start));
执行结果

时间单位: 微秒(microsecond)

序号间隔(微秒)
18
27
38
48
58
68
78
87
97
108
.......
大约执行时间为 7.7微妙 左右

非循环代码

ui::Button *pbtn_arr_[12] = { nullptr };
long long start = std::chrono::system_clock::now().time_since_epoch().count();

pbtn_arr_[0]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[1]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[2]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[3]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[4]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[5]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[6]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[7]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[8]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[9]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[10]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[11]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));

long long end = std::chrono::system_clock::now().time_since_epoch().count();
std::wstring sss =fmt::format(L"{}", (end-start));
执行结果

时间单位: 微秒(microsecond)

序号间隔(微秒)
121
221
323
422
523
621
721
822
922
1023
.......
大约执行时间为 22微妙 左右

结果

可见,如果能用循环,能大幅缩短程序执行时间,采用for循环后,降低执行时间约为 14 微妙。

代码分析

分析下面代码的特点

pbtn_arr_[10]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
pbtn_arr_[11]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));

其中,每次需要绑定控件时,都需重复下面的代码

= 
  dynamic_cast<
  >(FindControl();

显然,我们可以把它进一步优化。
于是将上面的代码pbtn_arr_[10] = dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));改为下面的形式:

find_control2(std::wstring(L"btn_blue"), btn_arr[11]);

其中,find_control2代码如下:

<template<typename T>
void find_control2(const std::wstring&& str_name, T& args)
{
	// 取得传进来的参数类型
	using ele_type2 =  typename std::decay<T>::type;

	// 读取xml文件中的控件
	ui::Control* pctrl = nullptr;
	pctrl = FindControl(str_name);
	if (pctrl)
	{
		// 转为目标类型指针
		args = dynamic_cast<ele_type2>(pctrl);
	}
}

改进后的效率执行如何呢?

改进后的时间测试

优化前

ui::Button *btn_arr[12] = { nullptr };
long long start = std::chrono::system_clock::now().time_since_epoch().count();

btn_arr[0]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[1]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[2]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[3]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[4]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[5]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[6]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[7]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[8]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[9]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[10]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));
btn_arr[11]	= dynamic_cast<ui::Button*>(FindControl(L"btn_blue"));

long long end = std::chrono::system_clock::now().time_since_epoch().count();
std::wstring sss =fmt::format(L"{}", (end-start));
prichedit_show_->SetText(sss);
执行结果

时间单位: 微秒(microsecond)

序号间隔(微秒)
121
221
323
422
523
621
721
822
924
1023
.......
大约执行时间为 22微妙 左右

优化后

ui::Button *btn_arr[12] = { nullptr };
long long start = std::chrono::system_clock::now().time_since_epoch().count();

find_control2(std::wstring(L"btn_blue"), btn_arr[0]);
find_control2(std::wstring(L"btn_blue"), btn_arr[1]);
find_control2(std::wstring(L"btn_blue"), btn_arr[2]);
find_control2(std::wstring(L"btn_blue"), btn_arr[3]);
find_control2(std::wstring(L"btn_blue"), btn_arr[4]);
find_control2(std::wstring(L"btn_blue"), btn_arr[5]);
find_control2(std::wstring(L"btn_blue"), btn_arr[6]);
find_control2(std::wstring(L"btn_blue"), btn_arr[7]);
find_control2(std::wstring(L"btn_blue"), btn_arr[8]);
find_control2(std::wstring(L"btn_blue"), btn_arr[9]);
find_control2(std::wstring(L"btn_blue"), btn_arr[10]);
find_control2(std::wstring(L"btn_blue"), btn_arr[11]);

long long end = std::chrono::system_clock::now().time_since_epoch().count();
std::wstring sss =fmt::format(L"{}", (end-start));
prichedit_show_->SetText(sss);
执行结果

时间单位: 微秒(microsecond)

序号间隔(微秒)
121
221
320
418
519
620
718
820
919
1020
.......
大约执行时间为 19微妙 左右

时间分析

优化后,程序执行时间缩短了约 2~3 毫秒,但是代码量却节省不少。 且易于维护。好处多多。

结论

  • for可以再一定程度上(实际为准)缩短执行时间
  • 尽量简化代码,方便维护,缩短程序执行时间

继续优化

采用find_control2方式,已经能明显看到效果了。但是,依然还会写很多重复代码,继续优化。

优化后

find_control3 函数

find_control3为优化后的函数,函数体如下:

template<typename T>
	void find_control3(const  std::wstring name_arr[], T** t)
	{
		// 控件name个数
		unsigned int name_len = sizeof(name_arr) / sizeof(std::wstring);
		// 控件个数
		unsigned int t_len = sizeof(t) / sizeof(T);

		if (0 == name_len || 0 == t_len)
			return;

		// 避免越界
		unsigned int min_len = (name_len > t_len) ? t_len : name_len;
		for (unsigned int index = 0; index < min_len; ++index)
		{
			find_control2(name_arr[index], t[index]);
		}		
	}

find_control3需要结合find_control2使用
调用方式如下

ui::Button *btn_arr[12] = { nullptr };
std::wstring name_arr2[] = 
{
	L"btn_blue",
	L"btn_blue",
	L"btn_blue",
	L"btn_blue",
	L"btn_blue",
	L"btn_blue",

	L"btn_blue",
	L"btn_blue",
	L"btn_blue",
	L"btn_blue",
	L"btn_blue",
	L"btn_blue"
};
find_control3(name_arr2, btn_arr);

执行结果

时间单位: 微秒(microsecond)

序号间隔(微秒)
12
22
32
42
52
62
72
82
92
102
.......
大约执行时间为 2微妙 左右.

哇瑟, 这差太多了,执行时间瞬间又2位数将为个位数,且为2微秒。 最终的改进结果:

casedecrease
相对for75%
相对使用索引95%

结论

  • 模板是个好东西,不知道你用了多少
  • 代码优化,极为重要
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值