我们应该搞清楚分支预测

分支预测的英文名字是「Branch Prediction

大家可以在Google上搜索这个关键字,可以看到关于分支预测的很多内容,不过要搞清楚分支预测如何工作的,才是问题的关键。

a5081a68d94124cecde979f2f4e4caea.png

分支预测对程序的影响

我们来看看下面的两段代码

代码1

#include <algorithm>
#include <ctime>
#include <iostream>
int main()
{// Generate dataconst unsigned arraySize = 32768;int data[arraySize];for (unsigned c = 0; c < arraySize; ++c)data[c] = std::rand() % 256;// !!! With this, the next loop runs faster.//std::sort(data, data + arraySize);// Testclock_t start = clock();long long sum = 0;for (unsigned i = 0; i < 100000; ++i) {for (unsigned c = 0; c < arraySize; ++c) { // Primary loopif (data[c] >= 128) sum += data[c];}}double elapsedTime = static_cast<double>(clock()-start) / CLOCKS_PER_SEC;std::cout << elapsedTime << '\n';std::cout << "sum = " << sum << '\n';
}

执行结果

@ubuntu:/data/study$ g++ fenzhi.cpp && ./a.out
21.6046
sum = 314931600000

代码2

#include <algorithm>
#include <ctime>
#include <iostream>
int main()
{// Generate dataconst unsigned arraySize = 32768;int data[arraySize];for (unsigned c = 0; c < arraySize; ++c)data[c] = std::rand() % 256;// !!! With this, the next loop runs faster.std::sort(data, data + arraySize);// Testclock_t start = clock();long long sum = 0;for (unsigned i = 0; i < 100000; ++i) {for (unsigned c = 0; c < arraySize; ++c) { // Primary loopif (data[c] >= 128) sum += data[c];}}double elapsedTime = static_cast<double>(clock()-start) / CLOCKS_PER_SEC;std::cout << elapsedTime << '\n';std::cout << "sum = " << sum << '\n';
}

执行结果:

@ubuntu:/data/study$ g++ fenzhi.cpp && ./a.out
8.52157
sum = 314931600000

第一段代码生成随机数组后,没有进行排序,第二段代码对随机的数组进行排序,执行的时间上发生了非常大的差异。

a30c5a80a7e057b14f939f30ccf1c672.png

所以,他们发生了什么事情呢?

导致他们结果不同的原因,就是分支预测,分支预测是CPU处理器对程序的一种预测,和CPU架构有关系,现在的很多处理器都有分支预测的功能。

CPU在执行这段代码的时候

if (data[c] >= 128) sum += data[c];

CPU会有一个提前预测机制,比如前面的执行结果都是true,那么下一次在判断if的时候,就会默认认为是true来处理,让下面的几条指令提前进入预装。

当然,这个判断不会影响实际的结果输出,这个判断只是为了让CPU并行执行代码。

CPU执行一条指令分为几个阶段

d8e8b1bd76663ca2e02e69b05d534352.png

既然是分阶段执行,也就是我们正常说的pipeline(流水线执行)。

流水线的工人只要完成自己负责的内容就好了,没有必要去关心其他的人处理。

那如果我有一段代码,如下:

int a = 0;
a += 1;
a += 2;
a += 3;

eada7f47a2a07631d7c3f7f1dd6c4c1c.png

ce865c4479d938b1fb14b0c95bbf9e94.png

从这个图上我们可以看到,我们认为是在执行 a = 0结束后,才会执行a+=1。

但是实际CPU是在执行a=0的第一条执行后,马上就去执行a+=1的第一条指令了。

也就因为这样,执行速度上得到了大幅度的提升。

但是对于if() 语言,在没有分支预测的时候,我们需要等待if()执行出现结果后才能继续执行下一个代码。

48d53667ca7f3aadaa3e792eda63222d.png

如果存在分支预测的情况

4db692c7779c4165865812ee1b665080.png

通过比较我们可以发现,如果存在分支预测的时候,就让执行速度变快了。

b678afc5ed27b3f34c79e35f439f0548.png

那如果预测失败,会不会就影响了执行的时间,答案是肯定的。

在前面的例子中,没有对数组排序的情况下,分支预测大部分都会是失败的,这个时候就会在执行结束后重新取指令执行,会严重影响执行效率。

而在排序后的例子中,分支预测一直处于成功的状态,CPU的执行速率得到大幅度的提升。

da765f745826969aedaa76225d44be97.png

如果解决分支预测引起的性能下降

分支预测一定会存在一定的能性下降,想让性能提升的方法就是不要使用这个该死的if语句。

比如,上面的代码,我们可以修改成这样

#include <algorithm>
#include <ctime>
#include <iostream>
int main()
{// Generate dataconst unsigned arraySize = 32768;int data[arraySize];for (unsigned c = 0; c < arraySize; ++c)data[c] = std::rand() % 256;// !!! With this, the next loop runs faster.//std::sort(data, data + arraySize);// Testclock_t start = clock();long long sum = 0;for (unsigned i = 0; i < 100000; ++i) {for (unsigned c = 0; c < arraySize; ++c) { // Primary loopint t = (data[c] - 128) >> 31;sum += ~t & data[c];}}double elapsedTime = static_cast<double>(clock()-start) / CLOCKS_PER_SEC;std::cout << elapsedTime << '\n';std::cout << "sum = " << sum << '\n';
}

比如,我们看到的绝对值代码,里面也用了这样的思想

/*** abs - return absolute value of an argument* @x: the value. If it is unsigned type, it is converted to signed type first.* char is treated as if it was signed (regardless of whether it really is)* but the macro's return type is preserved as char.** Return: an absolute value of x.*/
#define abs(x) __abs_choose_expr(x, long long, \__abs_choose_expr(x, long, \__abs_choose_expr(x, int, \__abs_choose_expr(x, short, \__abs_choose_expr(x, char, \__builtin_choose_expr( \__builtin_types_compatible_p(typeof(x), char), \(char)({ signed char __x = (x); __x<0?-__x:__x; }), \((void)0)))))))#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \__builtin_types_compatible_p(typeof(x), signed type) || \__builtin_types_compatible_p(typeof(x), unsigned type), \({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)

当然,你也可以这样写

int abs(int i){if(i<0)return ~(--i);return i;
}

所以说,计算机的尽头是数学

参考:

https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array/11227902#11227902

https://blog.csdn.net/loongshawn/article/details/118339009

https://blog.csdn.net/DBC_121/article/details/105360658

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/464537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Intent介绍及Intent在Activity中的使用方法

1.Intent的实现过程   在Android中&#xff0c;Intent不仅可用于应用程序之间的交互&#xff0c;也可用于应用程序内部的Activity/Service之间的交互。   Intent负责对应用中一次操作进行描述&#xff0c;描述内容包括动作以及动作所涉及的数据&#xff0c;Android中的In…

程序结束后去哪儿了?

大家好&#xff0c;我是写代码的篮球球痴&#xff0c;转发一篇卓老师的文章&#xff0c;文章中的内容我之前做单片机的时候也有遇到过。推荐给大家看看~简 介&#xff1a; 对于嵌入式系统&#xff0c;如果没有运行RTOS&#xff0c;那么程序开发中的 主函数&#xff08;main()&a…

CodeSmith终极玩法

CodeSmith是一个模仿asp.net运行机制的代码生成器, 运行时分析模板(相当aspx文件)的预编译指令和主体内容, 生成一个继承自CodeSmith.Engine.CodeTemplate(相当于System.Web.UI.Page)或者一个在Inherites预编译指令指定的类(相当于CodeBehind类)的源码, 且把它编译. 然后把这个…

bom与dom

区别 BOM&#xff08;Browser Object Model&#xff09; BOM 即浏览器对象模型&#xff0c;BOM没有相关标准&#xff0c;BOM的最核心对象是window对象。window对象既为javascript访问浏览器提供API&#xff0c;同时在ECMAScript中充当Global对象。BOM和浏览器关系密切&#xff…

有些事不用听别人的

今天在群里跟几个朋友聊天&#xff0c;然后说了自己的想法&#xff0c;最近很多人在说公众号不会有好的发展&#xff0c;写文章也是没有出路的。不过这个是事实。短视频才是可能是出路&#xff0c;短视频是个很大的蛋糕&#xff0c;从表达方式上来说&#xff0c;视频的表达方式…

25个优秀的设计机构网站设计案例

今天&#xff0c;我们一起来欣赏网站设计工作室自己的网站。设计公司的网站除了要能够吸引客户以外&#xff0c;还要通过他们自己的网站向客户展示他们的设计理念和风格。这里收集的25个优秀的设计机构网站既有清爽简洁风格的&#xff0c;也有色彩丰富&#xff0c;图文并茂的&a…

一个适用各类场合的Makefile模板

1.写在前面对于Windows下开发&#xff0c;很多IDE都集成了编译器&#xff0c;如Visual Studio&#xff0c;提供了“一键编译”&#xff0c;编码完成后只需一个操作即可完成编译、链接、生成目标文件。Linux开发与Windows不同&#xff0c;Linux下一般用的的gcc/g编译器&#xff…

毕业十年|我的嵌入式AI学习路线(笔记、代码)

嵌入式从业者接下来会有怎样的黄金十年&#xff1f;在物联网和人工智能的促进下&#xff0c;嵌入式在未来的5-10年内会迎来更多的发展机会&#xff0c;一方面嵌入式开发会迎来更多的应用场景&#xff0c;另一方面嵌入式开发的技术体系也会逐渐丰富&#xff0c;从而拓展物联网开…

在艰苦年代,买不起万用表,怎么测量电路电压?

如何测量电压&#xff1f;有这样一张图片&#xff1a;用舌头来测量&#xff1f;开玩笑的吧&#xff01;不过这张照片勾起了我的回忆&#xff1a;有一位玩电子的老前辈&#xff0c;现在已经70多岁了。和他聊天&#xff0c;他说&#xff0c;当年他们玩电子&#xff0c;条件非常艰…

VBA学习_5:流程控制

1、If If Range("B2").Value >60 Then Range("C2").Value "及格" Else Range("C2").Value"不及格"如果。。。那么。。。。否则。。。。 If Range("B2").Value > 60 ThenRange("C2").Value "…

嵌入式的薪资还是挺低的

我最近和一个比较好的朋友聊天&#xff0c;我这个朋友在一家比较传统的公司&#xff0c;在这个公司做嵌入式软件开发&#xff0c;偏系统方向的。然后最近拿到了几个不错的offer&#xff0c;让我帮忙看看。这几个offer我就不发出来给大家看了。可以肯定的是&#xff0c;这几个of…

新手必看!单片机掉电检测与数据掉电保存方案

单片机在正常工作时&#xff0c;因某种原因造成突然掉电&#xff0c;将会丢失数据存储器&#xff08;RAM&#xff09;里的数据。在某些应用场合如测量、控制等领域&#xff0c;单片机正常工作中采集和运算出一些重要数据&#xff0c;待下次上电后需要恢复这些重要数据。因此&am…

Study Notes ASP.Net 之Theme Skin

基本概念&#xff1a; Theme 和 Skin用以定义页面中各个控件的显示样式&#xff0c;如字体大小&#xff0c;前/后景色等等。一个Theme可以包括多个Skin&#xff0c;一个Skin可以定义多个控件的样式。目的&#xff1a; 使得页面样式的制作可以与页面制作分工进行。<?xml:nam…

推荐一个值得加入C++开发者俱乐部

之前我有篇文章提起过&#xff0c;开始进入某厂是从0开始做项目的&#xff0c;当时看到那套SDK软件&#xff0c;而且97%都是用C写的&#xff0c;我的头都大了。后面也是坚持不断的学习&#xff0c;积累&#xff0c;修改&#xff0c;向身边同事请教&#xff0c;加入优秀社群学习…

DataGrid 完全攻略之四 (实现统计)

前台代码&#xff1a;html<% Page language"c#" Codebehind"UserCount.aspx.cs" AutoEventWireup"false" Inherits"MsDataGrid.UserCount" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >…

Window系统下安装Redis

下载Redis Redis官网只提供Linux版本&#xff0c;Windows版本只能去GitHub上下载 Redis官网下载地址&#xff1a;http://redis.io/download GitHub下载地址&#xff1a;https://github.com/MSOpenTech/redis/tags 安装Redis 创建redis文件夹&#xff0c;解压到此目录下&#xf…

iTunes“解决方案”发展历程及研究(上)

以下内容来自于我的《iTunes内容解决方案研究》的PPT&#xff0c;懒得往上敲字了&#xff0c;直接以图片的形式发布&#xff0c;有需要的&#xff0c;我可以提供pdf版本给你&#xff0c;版权所有

Linux下的memcpy函数

之前写过一篇关于 memcpy函数面试的文章几个简单的笔试题里面的代码使用的是char指针来实现&#xff0c;今天我们来看看Linux下面的memcpy函数&#xff0c;它的实现上还是有一些巧妙的。void * memcpy(void * dest, const void *src, size_t n) {if (!(((unsigned long) dest ^…

linux命令行抓取网页快照-(xvfb+CutyCapt)

linux命令行抓取网页快照-&#xff08;xvfbCutyCapt&#xff09;又一个 WordPress 博客Browse: Home / 2009 / 十一月 / linux命令行抓取网页快照-&#xff08;xvfbCutyCapt&#xff09;linux命令行抓取网页快照-&#xff08;xvfbCutyCapt&#xff09;By saymoon on 2009年11月…

php过waf木马,一款过waf的一句话木马分析 | CN-SEC 中文网

摘要中午&#xff0c;下班回来&#xff0c;就看一个朋友给我发了几个马儿 让我看看解解密码 很简单中午&#xff0c;下班回来&#xff0c;就看一个朋友给我发了几个马儿 让我看看解解密码 很简单猛不猛我不知道 那时候手机 太长的看着就烦 就回到家瞅瞅了首先我们看这…