一个提高N倍系统新能的编程点,却总是被普通开发们遗忘
位运算这个概念并不陌生,大多数程序员在进入这个领域的时候或多或少都接触过位运算,估计当时都写过不少练习题的。
位运算本身不难,困难的是大家没有学会在系统设计时用上它,提高系统性能,增加你的不可替代性。
就不做太多铺垫了,直接说下今天讲述的干货内容:

位运算使用场景
面试经常问
比如我曾经在面试腾讯的时候
O(1) 时间如何检测整数 n 是否是 2 的幂次?
在看一道Google面试题:
有64瓶药,其中63瓶是无毒的,一瓶是有毒的。如果做实验的小白鼠喝了有毒的药,3天后会死掉,当然喝了其它的药,包括同时喝几种就没事。现在只剩下3天时间,请问最少需要多少只小白鼠才能试出那瓶药有毒?
这就不用龙su啰嗦了吧,稳稳的都是和位运算有关的。
类似面试题目还有很多,一个不注意就会被撂倒。
这部分的题目整体难度不大,本身不是一个很大的知识点,但是很容易被大家忽略,今天龙su就拿出来好好说说,大家可要记住喔,不然…
系统设计经常用
喜欢看源码的同学就会注意到,经常在里面看到这样的代码。
lucene源码

redis源码

龙叔的源码

有没有发现这些代码惊人的相似,好的设计总是这样不谋而合。

看了这么多,想必大家已经知道这东西还是有些作用的,应该好好搞清楚他的原理。接下来就一起来盘他。
位运算原理
位 指的是比特位(bit),不是byte,所以位运算指的就是比特位计算。
CPU所有计算都是二进制的计算,一个高性能的服务一定是把CPU资源利用到极致,也就是用最少资源换取最大收益。
当然随着现代CPU的计算速度不断加快,很多人在设计系统的时候完全不会去考虑这些性能点,然而真正的高并发系统都是极致性能的。
看看我们日常开发都是啥样的,只要不涉及到高并发,开发代码就算是一坨屎,也没关系,大多数人都是在这坨屎上继续CRUD,也就会变成了一大坨。
没办法,老板只看结果,懒得管你的代码是什么样的。哎呀,好像暴露了龙叔是个CRUD菜鸡选手。
等到有一天发现加机器加到扛不住了,这时候就是最幸运的一批程序员诞生的时候,必须开始重构系统。为什么最幸运,大家都知道了吧?机会不是天天有的,这就是千载难逢的良机啊。
哈,好像有点说远了。
在计算机世界里,万物皆0、1,0、1生万物。万物到0、1的过程叫做编码。
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机中用一个数的最高位存放符号, 正数为0, 负数为1。
计算机中对数字的编码表示有三种方式:原码,反码,补码:
原码:原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1。比如十进制3如果用8个二进制位来表示就是 00000011, -3就是 10000011。
反码:反码表示方法:正数的反码是其本身;负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
补码:补码表示方法:正数的补码是其本身;负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。 (即在反码的基础上+1)
这三种是编码方式,但是在计算机系统中,数值一律用补码来表示(存储)。
举个例子:
1. 10
原码 反码 补码
00001010 --> 00001010 --> 00001010
2. -15
10001111 --> 11110000 --> 11110001
说完了数据编码,基本已经知道一个数据是怎么存储在计算机中的,接下来就看看数据比特位之间是如何计算的。
各种编程语言都提供了对补码的二进制位直接进行运算的方法,即位运算。
| 符号 | 描述 | 规则 |
|---|---|---|
| & | 与 | 相同位的两个数字都为1,则为1;若有一个不为1,则为0。 |
| | | 或 | 相同位只要一个为1即为1。 |
| ~ | 非 | 0和1全部取反。 |
| ^ | 亦或 | 相同位不同则为1,相同则为0。 |
| << | 左移 | a << b就表示把a转为二进制后左移b位(在后面添b个0)。 |
| >> | 右移 | a >> b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。 |
举几个例子
10 & -15 = 00001010 & 11110001

按位进行相与,相同为1则为1,否则为0,最终算的结果为00000000 即0
10 & 15 = 00001010 & 00001111

按位进行相与,相同为1则为1,否则为0,最终算的结果为00001010 即10
10 | 15 = 00001010 | 00001111

按位进行或逻辑,相同位只要一个为1即为1 ,00001111即15
15>>2

二进制右移2位,左边填符号号位,右边抹掉,得到00000011 即3
15<<2

二进制左移2位,左边抹掉,符号位不变,右边填0,得到00111100
原理还是比较简单,主要就是对比特位进行逻辑操作。
位运算为什么那么快?
看到这里其实大多数人已经明白为什么位运算快了,但暖心的龙叔还是在啰嗦下原因,就算是锦上添花(画蛇添足)了。
- 存储更友好,比特位存储,不用转换后在存储
- CPU更友好,直接比特位操作,减少机器数到比特位的转换
- 寻址次数更少,左移一位就乘2
说一个搜索里面位运算带来的性能提升
比如你在百度搜索 广东富婆 ,分词会分为 广东 富婆 两个词,分别从两个倒排中召回,假设 广东 这个词召回了100w个doc,富婆 召回了1000W个。
此时两个doc链会进行一个合并,合并的返回结果是存在广东的同时又要存在富婆的doc。
这个合并如果是通过比特位的方式操作的话,一个64位的CPU一个指令周期可以处理64个doc,如果采用普通合并的话,一次只能合并一个doc,这个性能提升很明显的吧,是不是感觉高性能有点意思了。
像这种性能上的提升,是无法通过增加机器解决的。
总结
这次内容不难,讲出来是希望大家在做系统设计时,性能考虑不是简单的加机器,而是真的把CPU价值最大化。
小改动、大效果,一些小的改动,会对性能提升产生很多的效果。反正我这次设计时基本把一些计算都改为了位运算。
我是龙叔,一个在互联网大器晚成的设计师,我们下期见。喜欢我,记得关注我。
一个提高N倍系统新能的编程点,却总是被普通开发们遗忘的更多相关文章
- [原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥)
[原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥) nohacks 发表于 2016-5-29 17:12:51 https:// ...
- 将Web应用性能提高十倍的10条建议
导读 提高 web 应用的性能从来没有比现在更重要过.网络经济的比重一直在增长:全球经济超过 5% 的价值是在因特网上产生的(数据参见下面的资料).这个时刻在线的超连接世界意味着用户对其的期望值也处于 ...
- 将 Web 应用性能提高十倍的10条建议
提高 web 应用的性能从来没有比现在更重要过.网络经济的比重一直在增长:全球经济超过 5% 的价值是在因特网上产生的(数据参见下面的资料).这个时刻在线的超连接世界意味着用户对其的期望值也处于历史上 ...
- 【转】Vim速查表-帮你提高N倍效率
Vim速查表-帮你提高N倍效率 转自:https://www.jianshu.com/p/6aa2e0e39f99 去年上半年开始全面使用linux进行开发和娱乐了,现在已经回不去windows了. ...
- 【Android】一种提高Android应用进程存活率新方法
[Android]一种提高Android应用进程存活率新方法 SkySeraph Jun. 19st 2016 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph ...
- 王家林 Spark公开课大讲坛第一期:Spark把云计算大数据速度提高100倍以上
王家林 Spark公开课大讲坛第一期:Spark把云计算大数据速度提高100倍以上 http://edu.51cto.com/lesson/id-30815.html Spark实战高手之路 系列书籍 ...
- iOS开发——新特性OC篇&IOS9 系统新特性
IOS9 系统新特性 2015年6月89号凌晨召开的WWDC 2015苹果开发者大会发布了全新的iOS 9系统,PC6小编今天给大家整理了这次iOS9的系统更新带来了哪些新的功能与升级,本次新功能一览 ...
- 如何提高Web应用系统的性能?
随着互联网信息技术的发展,人们逐渐开始习惯在网络上交友.购物.学习.娱乐.工作,甚至是找工作.因此市场对网站的响应速度也提出了新的要求,提高Web应用系统的性能成为急需解决的关键问题.本文将会给出一些 ...
- 使用 PyTorch Lightning 将深度学习管道速度提高 10 倍
前言 本文介绍了如何使用 PyTorch Lightning 构建高效且快速的深度学习管道,主要包括有为什么优化深度学习管道很重要.使用 PyTorch Lightning 加快实验周期的六种 ...
随机推荐
- JavaScript学习系列博客_27_JavaScript 遍历数组
遍历数组 - 遍历数组就是将数组中元素都获取到 - 一般情况我们都是使用for循环来遍历数组: - 使用forEach()方法来遍历数组(不兼容IE8) forEach()方法需要一个回调函数(由我们 ...
- C++ Templates (1.7 总结 Summary)
返回完整目录 目录 1.7 总结 Summary 1.7 总结 Summary 函数模板定义了一系列不同模板实参的函数 当传递实参给依赖于模板参数的函数参数,函数模板推断模板参数并实例化相应的参数类型 ...
- SpringBoot项目 使用Jenkins进行自动化部署 gitlab打tag 生产测试环境使用 含配置中心
脚本 node('master') { def mvnHome = tool 'maven11-free' def gitUrl = "http://gitlab.wdcloud.cc:10 ...
- 兼容低版本IE浏览器的一些心得体会(持续更新)
前言: 近期工作中,突然被要求改别人的代码,其中有一项就是兼容IE低版本浏览器,所以优雅降级吧. 我相信兼容低版本IE是许多前端开发的噩梦,尤其是改别人写的代码,更是痛不欲生. 本文将介绍一些本人兼容 ...
- 《MySQL数据库》MySQL主从复制搭建与原理
前言 主从复制:两台或者更多的数据库实例,通过二进制日志,实现数据同步.为什么需要主从复制,主从复制的作用是什么,答:为了预防灾难. 搭建 第一步:准备多实例环境.如何创建多实例见: 第二步:确保每一 ...
- js实现csv下载
var TableDatas = '数据源';function getCSV(){ if(this.TableDatas.length === 0){ alert("没有数据呀呀呀呀!&q ...
- 使用echarts 轻松搞定各种后台数据统计
之前接到老大一个需求,需要将公私生态系统构建一个日志系统,统计公有云.私有云还有其他工具平台(如禅道,jenkins)的用户登录信息,并使用图标的形式动态显示,之前刚入门的时候接触过echarts 这 ...
- Oracle数据库的文件以及Oracle体系架构
第一部分.Oracle数据库的文件 1.参数文件:控制实例的行为的参数的集合 参数文件的作用 设定数据库的限制 设置用户或者进程的限制 设定数据库资源的限制 调整系统的性能 主要的参数文件 SGA_T ...
- 阿里Java中级开发测试相关试题及答案
------------恢复内容开始------------ 1.JSP文件上传的HTML标签代码定义是? A. <input type="text" name=" ...
- checkbox手动样式改变
.image_input_checkbox{ width:18px; height:18px; display: inline-block; vertical-align: middle; -webk ...