从代码整洁的角度考虑,对于不同的值将调用相同参数的不同函数,我们通常可以通过建立从值到对应函数指针的哈希表,从而将if else消除。但实际可能使性能更低,以下是测试例子。

原因在于,if else分支预测不正确虽然可能使指令流水线几条指令执行错误,但通过哈希表的方式,增加了计算哈希值、查询哈希表以及通过函数指针调用的开销,从而可能使得调用过程慢了更多。

以下比较了四种方法的计算性能:

  1. if else

  2. unordered_map

  3. switch case

  4. function pointer array

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 10;
constexpr int COUNT = 10000000;
long long a = 0;
void targetFunc1(){
for(int i = 0; i < N; i++){
a++;
}
} void targetFunc2(){
for(int i = 0; i < N; i++){
a++;
}
} void targetFunc3(){
for(int i = 0; i < N; i++){
a++;
}
} void targetFunc4(){
for(int i = 0; i < N; i++){
a++;
}
} void targetFunc5(){
for(int i = 0; i < N; i++){
a++;
}
} void targetFunc6(){
for(int i = 0; i < N; i++){
a++;
}
} // 1. if else void test1(int a){
if(a == 1) targetFunc1();
if(a == 2) targetFunc2();
if(a == 3) targetFunc3();
if(a == 4) targetFunc4();
if(a == 5) targetFunc5();
if(a == 6) targetFunc6();
} std::unordered_map<int, void(*)()> funcs = {
{1, targetFunc1},
{2, targetFunc2},
{3, targetFunc3},
{4, targetFunc4},
{5, targetFunc5},
{6, targetFunc6}
}; // 2. unordered_map void test2(int a){
funcs[a]();
} // 3. switch case void test3(int a){
switch(a){
case 1:
targetFunc1();
break;
case 2:
targetFunc2();
break;
case 3:
targetFunc3();
break;
case 4:
targetFunc4();
break;
case 5:
targetFunc5();
break;
case 6:
targetFunc6();
break;
}
} // 4. function pointer array
void (*arr[6])(); void test4(int a){
arr[a-1]();
} void timeMeasure(void(*f)(int)){
auto begin = std::chrono::high_resolution_clock::now();
uint32_t iterations = 100;
for(uint32_t i = 0; i < iterations; ++i)
{
int index = rand() % 6 + 1;
f(index);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end-begin).count();
std::cout << duration << "ns total, average : " << duration / iterations << "ns." << std::endl;
} int main()
{ arr[0] = targetFunc1;
arr[1] = targetFunc2;
arr[2] = targetFunc3;
arr[3] = targetFunc4;
arr[4] = targetFunc5;
arr[5] = targetFunc6;
timeMeasure(test1);
std::cout<<a<<std::endl;
timeMeasure(test2);
std::cout<<a<<std::endl;
timeMeasure(test3);
std::cout<<a<<std::endl;
timeMeasure(test4);
std::cout<<a<<std::endl;
return 0;
}
16859ns total, average : 168ns.
1000
41576ns total, average : 415ns.
2000
13834ns total, average : 138ns.
3000
14368ns total, average : 143ns.
4000

结论:

  1. switch case和函数指针数组查表比if else实现的性能较高

  2. unordered_map查表导致性能降低。

C++ 性能反向优化——用哈希表unordered_map消除if else导致性能降低。的更多相关文章

  1. [PHP内核探索]PHP中的哈希表

    在PHP内核中,其中一个很重要的数据结构就是HashTable.我们常用的数组,在内核中就是用HashTable来实现.那么,PHP的HashTable是怎么实现的呢?最近在看HashTable的数据 ...

  2. 【算法】哈希表的诞生(Java)

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...

  3. 性能调优7:多表连接 - join

    在产品环境中,往往存在着大量的表连接情景,不管是inner join.outer join.cross join和full join(逻辑连接符号),在内部都会转化为物理连接(Physical Joi ...

  4. 源码:Java集合源码之:哈希表(二)

    要想知道一个元素是否在数组或链表中,只能从前向后挨个对比,无论是数组还是链表,其对数据的查询表现都比较无力.在的二叉排序树中,还会将数据排序以进行二分查找,将时间复杂度从O(n)降低到O(lg n). ...

  5. 理解Golang哈希表Map的元素

    目录 概述 哈希函数 冲突解决 初始化 结构体 字面量 运行时 操作 访问 写入 扩容 删除 总结 在上一节中我们介绍了 数组和切片的实现原理,这一节会介绍 Golang 中的另一个集合元素 - 哈希 ...

  6. 6.MySQL优化---高级进阶之表的设计及优化

    转自互联网整理. 优化之路高级进阶——表的设计及优化 优化①:创建规范化表,消除数据冗余 数据库范式是确保数据库结构合理,满足各种查询需要.避免数据库操作异常的数据库设计方式.满足范式要求的表,称为规 ...

  7. STL的容器哈希表

    C++ STL中,哈希表对应的容器是 unordered_map(since C++ 11).根据 C++ 11 标准的推荐,用 unordered_map 代替 hash_map. 与Map的区别 ...

  8. mysql数据库性能优化(包括SQL,表结构,索引,缓存)

    优化目标减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当 ...

  9. MySQL 性能优化系列之一 单表预处理

    MySQL 性能优化系列之一 单表预处理 背景介绍 我们经常在写多表关联的SQL时,会想到 left jion(左关联),right jion(右关联),inner jion(内关联)等. 但是,当表 ...

  10. MySQL性能优化(五):分表

    原文:MySQL性能优化(五):分表 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/vbi ...

随机推荐

  1. Solo 独立开发者社区

    Solo 独立开发者社区是一个致力于帮助独立开发者发展的社区平台.平台上聚集了大量的独立开发者,他们在这个平台上分享着自己的开发经验.心得和技巧,同时也可以从其他人的分享中获得启发和帮助. 这个社区提 ...

  2. 基于 Impala 的高性能数仓实践之物化视图服务

    本文将主要介绍 NDH Impala 的物化视图实现. 接上篇,前两篇分别讲了执行引擎和虚拟数仓,它们是让一个 SQL 又快又好地执行的关键.但如果某些 SQL 过于复杂,比如多张大表进行 Join ...

  3. EasyDesktop 浏览器书签管理从未如此简单

    作为一名软件开发从业人员, 每天80%的时间都在与浏览器打交道, 一半的时间在用浏览器开发调试, 另一半时间则是在互联网上搜寻各种知识和资源. 为此, 我的浏览器书签栏存储和很多非常棒的链接, 多到2 ...

  4. C# Winform与JS交互

    一.C#调用JS函数 1.JS代码 < script language = "javascript" > function Hello(msg) { alert('我是 ...

  5. NSSCTF———Web(sql注入)

    [LitCTF 2023]这是什么?SQL !注一下 ! [SWPUCTF 2022 新生赛]ez_sql [GXYCTF 2019]BabySqli 点击右下角文章可跳转 [LitCTF 2023] ...

  6. 计算机网络中的检验和(checksum)(包括计算文件的检验和附有c++代码)

    介绍: 检验和(checksum),在数据处理和数据通信领域中,用于校验目的地一组数据项的和.它通常是以十六进制为数制表示的形式.如果校验和的数值超过十六进制的FF,也就是255. 就要求其补码作为校 ...

  7. 基于EasyTcp4Net开发一个功能较为完善的去持久化聊天软件

    之前自己写了一篇介绍TCP的一些常用的功能介绍和特征,并且用代码做了示例,最终开发了一个EasyTcp4Net的TCP工具库,其最大的特色就是使用了微软提供的高性能库中的一些数据结构来处理TCP数据. ...

  8. 实现一个终端文本编辑器来学习golang语言:第二章Raw模式下的输入输出

    从第二章开始,在每个小节的最后都会有一些代码实操作业,你可以选择自己完成(比较推荐),再对照我的实现方式,当然也可以直接看我的代码实现.不过,之后的各个功能实现,我都会基于我先前的代码实现版本,在它的 ...

  9. python高性能计算:cython入门代码

    三种实现的对比: (1)纯python x.py def is_prime(num): for j in range(2, num): if (num%j)==0: return False retu ...

  10. 【转载】 GPU地址空间的相关概念

    为了结合上篇 文章   https://www.cnblogs.com/devilmaycry812839668/p/13264080.html 对RTX显卡是否能够实现P2P通信功能,同时专业级别显 ...