这篇文章是对我看的科普视频的自我理解和转述,视频来自B站Up主:硬件茶谈。他关于内存数据流的一个视频,有兴趣的同学可以自己去看看。
背景
最近618,我也是顶着矿难装了一台电脑,很不幸,我…安全下山,可惜我买的是3050,网传矿老板都不买的显卡。组装之后也是很幸运的一次点亮,光是点亮还不足以满足我,因为我买电脑就是为了打游戏的,所以我就想知道其中那些配件会影响我的游戏体验,又分别影响哪个方面。
首先研究的就是硬盘,CPU,内存这三个配件的作用和关系,总所周知,不管什么东西,都是储存在硬盘里面的,游戏也不例外,游戏的存档,本体,Mod都会储存在硬盘里面。打开游戏时,CPU会将所需要用到的数据读取到内存中,然后就没有硬盘什么事情了,所以硬盘最能影响的就是我们打开游戏的时间,硬盘读写速度越快,我们就能有越多的时间来享受游戏,而不是停留在游戏开始界面,等他慢慢加载。
之后便是CPU和内存之间的数据交互了,CPU负责处理游戏数据,内存负责储存数据,分工合作,才能让我们有更好的游戏体验。但作为一个程序员我深知数据在传输的过程中可是不稳定的,在复杂的环境下很容易就会发生比特反转,如下:
这种问题可大可小,小的话,可能就是某个显示单元的颜色数据,差一点可能我们都发现不了,大的话,可能就会导致我们的电脑蓝屏。看到这里其实很多科班出生的同学都应该了解了,就是数据纠错,这是在写网络连接经常会遇到的问题。那么怎么解决呢?
传统方案
传统的解决方案就很实在,发一条数据不行就发两条呗,只要两条数据不一样,那我就知道数据是错误的还是正确的。虽然这个方法很简单,但是问题也很明显。
问题
- 万一错误的地方是同一个呢,那不就判断不出来了么;
- 虽然能快速的定位错误的位置,但是我不知道哪个是错的哪个是对的,只能再发一次数据,能判断错误却不能纠错;
改进
既然传两条数据还是不行,那就传三条,3是大于2但不能被2整除的最小整数,所以三条数据是可以判断哪条数据正确的最少数量。
这样,我们就能判断这个数据的正确版本应该是
,内存只需要储存这个数据就行了。
问题
- 还是原本的第一个问题,如果有两条数据,相同一个地方发生了比特反转,那我们最后储存的数据不就是错误的了么;
- 带宽利用率太低了,传输1bit的数据,需要2bit的数据作为检验,那么带宽的利用率才只有1/3。
理解
首先,我们在解决存在外界干扰的问题时,并不存在完美的方案,我们只能提高我们的正确率,但不可能确保100%,所以关于问题1,这种低概率发生事件,我们就暂时不考虑。
奇偶校验
为了解决上面的问题2,我们需要减少校验数据的校验码(在后面我统一称为纠错码),奇偶校验应运而生,我们在每段数据的开头加一个校验码。然后计算数据中1的个数,如果1的个数是奇数,那么校验码就变成1,如果1的个数是偶数,那么纠错码就变成0,这段二进制数的1的个数就一定是偶数。
就跟这张图一样,这段数据中的1的个数就是6,是偶数,所以纠错码就是0,整段二进制数的1的个数就是偶数,证明这段数据没有问题。
而另一张图,二进制数的1的个数是5,是奇数,所以数据是错误的,发生了比特翻转。这样,我们的校验码就从原来的”原数据的两倍“变成了”原数据的1/16倍“效率,占用的带宽大大减少了。
这个时候有同学会问,那如果在传输的过程中纠错码发生了错误怎么办。
其实你可以去改变纠错码看看,你会发现并没有什么影响,只不过会重新发送一边数据而已。
并不是纠错码保护了整组数据,而是纠错码改变了整组数据的奇偶性,纠错码也在这个整体中,也就是说,纠错码在保护数据的同时也保护了自己。
问题
- 虽然解决了带宽的问题,但是发现错误时,只能请求重发,也就是说只能判断错误,而不能纠错;
- 如果一组数据中两个位置同时发生比特翻转,那么奇偶校验也是不能发现的;
汉明码
为了解决上面的问题,有一个叫汉明的人发明了一种编码格式,我们就叫他汉明码,下面我们来讲解一下汉明码的原理。这时候需要有一点二分法的思维,我们要怎么去找到这个错误的比特呢,最快的方法就是用奇偶校验的方法检查一半数据,如果错误不在这一半数据中就会在另一半数据中,如下图所示:
仔细一想这样不就变成一数据一个纠错码了么,这显然不是汉明的初衷,这里我们要引进一个概念,我们先来玩一个游戏,有一只兔子藏在了下面的色块中,已知它不在黄色下面,但在红色和蓝色下面,那么请问,兔子在编号几的色块下面?
没错,兔子在编号6的色块下面。
然后把这两个思路整合到一起,为了方便我们理解,我先把原本的一维数据转化为二维数据
这种情况下,外加任何的纠错码,都不能让他和数据成为一个整体。所以我们需要调整数据的个数,让纠错码和数据仍然是一个二维数组,我们将原本4x4个数据变成了4x4-1个数据,然后将第一排第三列的数据作为纠错码
这个纠错码,校验的是后两列的数据
逻辑和之前一样,如果其中1的个数是奇数则纠错码为1,如果1的个数是偶数则纠错码为0。
然后将数据从4x4-1变成4x4-2,同时第一排第二列的数据做为纠错码出现,这个纠错码,纠错的数据部分如下
利用这两个纠错码,我们可以很轻松的定位错误的数据在哪一列,两个纠错码中1的个数的组合一共是四种,分别是:偶偶,奇偶,偶奇,奇奇。他们对应的错误的列数是:第一列,第三列,第二列,第四列。同理,我们也可以把第二排第一列和第三排第一列的数据作为校验码。并再次减少2个数据。这样我们就能通过错误数据的排列来精准定位数据了。
这里肯定有同学会问,这四种情况都会发现错误,这不合理啊,如果没有错误会怎么样呢?
问出这样问题的同学,首先恭喜你,你是在认真学习和思考的,但是你思考的还不够到位。因为我们同样可以利用上面的流程再增加一个纠错码。这个纠错码对应的就是整个二维数组。我们将数据在减少一个,变成4x4-5。然后我们将第一排第一列的数据作为纠错码出现
就这样,我们用五个纠错码就保护了这个4x4-5的数据,并且能让接收方通过这个方法纠错,而不是再发一遍。
这里比较严格的同学就会发问了,虽然这个汉明码能精准的定位错误数据,但是他的带宽利用率还不如奇偶校验呢!
不要被格式化的教育限制你的思想,我这个数组可以是4x4的,难道就不能是8x8么,或者16x16呢。
当然数据越多纠错码就越多,但是纠错码的占比会降低。但是数据多了,出现两次比特翻转的情况就会变多,这并不是我们想看到的。我们常见的ECC内存条中的纠错功能,用到的就是汉明码,一般数据大小为64bit,纠错码大小为12bit。
既然说到了两次比特翻转,之前奇偶校验不能解决的问题,我们来看看汉明码能否解决问题,下面是一个原始数据
在传输的过程中,其中第二排第四列和第三排第四列的两个数据,发生了比特翻转。变成了
首先,检测错误列
第一张图可以看出,1的个数是偶数,错误不在后两列;第二张图,1的个数也是偶数,错误不在第二,四列。那么错误就只能在第一列。
然后,检测错误行
第一张图可以看出,1的个数是奇数,错误在后两行;第二张图,1的个数也是奇数,错误在第二,四行。那么错误就只能在第四行。这样我们就知道了错误的比特在第四行第一列,显然这并不是我们一开始翻转的数据,所以汉明码并不能纠错二次比特翻转。但是整个数组的1的个数是偶数,证明整个数组是正确的,两个结果互相冲突,这说明,错误存在但错误的数据不止一个。其实这个结果是可以遇见的,因为每种对错的组合只能对应一个结果,所以不管这个数组上面有多少错误,最后排查出来的错误永远只会有一个。但是偶数次的比特翻转又不会影响整体数组的奇偶性,所以当偶数次比特翻转错误时,我们可以用汉明码来判断错误,但不能纠错。
写在结尾
初级篇的内容就讲到这里,下一篇文章,我们会沿着二分法,二进制的方向,深入了解汉明码的魅力所在,感兴趣的朋友也可以提前去b站观看视频 【硬件茶谈】。天道酬勤,与君共勉!