理解计算机

理解计算机

机械硬盘原理
术语
盘面、磁道、柱面、扇区、磁头、起停区、0磁道 盘面 : 由不同半径的磁道大致形成的一个平面,两面均可用于存储数据 磁道 : 特定半径的圆环,专门用来存储数据,磁道编号是从外向内以0开始顺序编号 柱面 : 同半径的磁道构成的叫柱面 扇区 : 构成磁道的基本单位,基本大小为512B 起停区 : 顾名思义,磁头开始读取数据或者结束读取数据的置放点,位于最内圈,不存放数据 磁头 : 紧贴盘面的上下面 0磁道 : 最外圈,离主轴最远的地方,硬盘数据的存放的开始点 块是操作系统与硬盘打交道虚拟出来的 页是操作系统与内存打交道虚拟出来的 早期系统关机之前会运行一个叫parking的程序,其作用是让磁头回到起停区 现代设计中,硬盘不工作时,磁头停留在起停区,当需要从硬盘读写数据时,磁盘开始旋转。旋转速度达到额定的高速时,磁头就会因为旋转产生的气流微微抬起,离开石墨保护层,从而开始向盘片存放数据的地方开始移动。 这个距离大概是纳米级别,离盘面越近,读写效率越高,也能使盘面达到足够强的磁化。 如下是磁头的大致形象图,从上到下依次标号0~7 ----- --| ----- ----- --| ----- ----- --| ----- ----- --| -----
性质
柱面数 = 磁道数 磁头数 = 盘面数 × 2 扇区 = 512B 磁道是看不见的,只是一些以特殊形式磁化了的磁化区 机械硬盘大小 = 柱面数 × 磁头数 × 扇区数 × 512B 块 = 512B × 2^n,也就是块等于多个扇区的大小
概念
读/写是按照柱面进行的,即磁头读/写数据时首先在同一柱面从0磁头开始进行的,依次向下在同一柱面的不同盘面上进行操作, 只在同一柱面的所有磁头全部读/写完毕才移动到下一柱面。因为选取磁头只需要电子切换,而选取柱面必须通过机械切换。 电子切换相当快,比机械切换快的多。 数据的读/写按柱面进行,而不按盘面进行。
怎样唯一确定一段数据的位置?
柱面号 + 磁头号 + 扇区号
访盘请求完成过程
当需要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要 读的数据在哪个磁道,哪个扇区。 为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点: 1)首先必须找到柱面,即磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间 2)然后目标扇区旋转到磁头下,即磁盘旋转将目标扇区旋转到磁头下。这个过程耗费的时间叫做旋转时间。 即一次访盘请求(读/写)完成过程由三个动作组成: 1)寻道(时间):磁头移动定位到指定磁道 2)旋转延迟(时间):等待指定扇区从磁头下旋转经过 3)数据传输(时间):数据在磁盘与内存之间的实际传输 因此在磁盘上读取扇区数据(一块数据)所需时间: Ti/o=Ts +Tr + n *Tt Ts 为寻道时间 Tr 为旋转时间 Tt 为数据传输时间
数据的读写口诀
从外到内(0磁道开始,即最外圈开始),从上到下(0磁头开始往下切换磁头)
磁盘碎片的产生
问题起源:扇区的大小有限,数据刚好存放在整数个扇区当然很完美,但是大多时候会超出,而这时候相对于删除当前文件,新 建文件再写入。无疑打碎文件更好,但是这同时增加了查找数据的时间。 同时需要注意磁盘外圈因为线速度大,所有外侧的读取速度会比内侧的数据快很多! 所有很多时候我们并不是一次寻道就能拿到数据,多数是数十次甚至更多。
Linux术语的英文表述
heads -> 盘面 sectors -> 扇区 cylindres -> 柱面 每个扇区大小为0.5KB,也就是能存放 512 个英文字母 计算公式: 硬盘体积 = 磁面个数 * 扇区个数 * 每个扇区的大小512 * 柱面个数
为什么要有磁盘块?
  1. 聚合多个扇区方便寻址
  1. 作为抽象层, 让操作系统忽略扇区概念, 认为块是最小单位
为什么C盘不能太满?
机械硬盘时代
第一点,文件少,有利于磁头在一个很小的范围工作,效率更高 第二点,无多余程序,产生的磁盘碎片少 第三点,较小的数据量,碎片整理的时间大幅减小 第四点,C盘含有系统引导文件,通常位于磁盘的外圈,读写速度快
 
 
固态硬盘
第一点,固态硬盘无碎片,也千万不能做碎片整理容易缩短使用寿命 第二点,按照以前的思路已经行不通了,因为固态硬盘的使用寿命和WAF成反比,而WAF在占用空间小于80%的时候, 均呈线性缓慢增长,一旦占用空间达到80%就会急剧上升,导致影响硬盘使用寿命
系统引导方式
传统MBR+BIOS启动
MBR最重要的就是主引导记录,存在于磁盘第一个扇区中,故总大小为0.5K,主引导记录包括: - 引导代码(ASM) 446B - 主分区信息,至多 512 - 446 - 2 = 64B,每个分区表项大小为 16B - 硬盘有效标志 2B 限制: MBR分区表中逻辑块地址采用32进制数表示,因此一共可以表示 2^32 个逻辑块地址,如果一个扇区大小为 512B,那么 硬盘分区的最大容量为 2TB 当使用GPT分区时,同样有MBR分区(或者叫PMBR),该分区的作用是: 1)保护GPT分区免受MBR类工具损坏,因为有PMBR,工具会将GPT分区看做未知格式的磁盘 2)一种兼容处理方法
现代GPT+UEFI启动
GPT的特点 1) 分区信息在分区中 2) 同时存在GPT分区表,相当于备份了GPT分区表 3) 不限制分区数量 4) 分区最大容量不止2TB,2^64*512B UEFI为c语言编写,已经相当于一个微型操作系统,同时具备文件系统的支持,可直接读取FAT分区的文件,UEFI通过查看GPT分区表启动系统 BIOS -> 无法识别GPT分区 UEFI -> 能够同时识别MBR分区和GPT分区 同时,因为UEFI可直接识别FAT32文件类型,那么我们可以将windows安装程序做成efi类型应用程序,然后把他放到任意 fat分区中运行即可
优缺点
BIOS最主要的缺点,就是对扇区的操作远远比不上像UEFI那样对分区中文件的操作直观简单 UEFI下,不再需要主引导记录,不再需要活动分区,只需要复制安装一个文件到一个FAT32分区中,然后从这个分区启动
ROM、RAM、FLASH 的区别
ROM 和 RAM 都是半导体存储器,ROM 即 Read Only Memory,RAM 即 Random Access Memory,ROM 在系统停止供电的时候仍然可以保持数据,而 RAM 通常是在断电之后就丢失数据,典型的 RAM 就是计算机的内存。 RAM 有两种,即 SRAM 和 DRAM,SRAM 是目前读写最快的存储设备,常被用于计算机 cpu 的一级、二级缓存。DRAM 读写速度相较 SRAM 要慢不少,但是价格也相对便宜很多。DRAM 常被用于计算机内存。 DRAM 的存储单元为0还是1取决于电容是否有电荷,有电荷代表1,无电荷代表0。但代表1的电容容易放电,代表0的电容容易吸收电荷,所以需要定时"刷新",将大于1/2电荷的电容充电,将小于1/2电荷的电容放电。 ROM 有一些早期产品例如 PROM(可编程 ROM),数据一旦写入则不可更改。也有例如 EPROM,需要用紫外线擦除其中的数据。还有 EEPROM,支持电子擦除。 FLASH 是一种结合了 ROM 和 RAM 优点的产品,它不仅支持电子擦除,也能够在系统停止供电后保持数据。FLASH 目前常取代 ROM 被用于 U盘等,被广泛用于嵌入式系统。
cpu频率、缓存、核心以及线程数
cpu - 即中央处理器,cpu每个时钟周期完成的指令数是固定的,cpu频率越高也就意味着完成速度越快,它决定了 cpu 相同架构下单核心的处理速度。而cpu缓存决定了在高压(cpu占有率达到85%以上)的处理速度。cpu缓存分为一级缓存和二级缓存,是RAM的一种(SRAM),读写速度远远高于内存(DRAM),价格也远远高于DRAM。cpu的缓存通常很小,例如 L1-L2-L3-L4 四个缓存条,速度从大到小,体积从小到大,L1一般几十KB,L2一般几MB,L3一般5-30MB不等。
一般来说,核心数等于线程数,即同时能处理的任务数。线程是一个逻辑上的概念。AMD的处理器一个核心对应一个线程。而Intel的处理器一个核心对应多个线程(超线程技术),但是Intel每个核心均比AMD强太多,单核能力出众,因而4核8线程的Intel处理器也比AMD的8核FX贵上一倍。注意这里的线程是硬件层面的线程,指CPU同时能够处理的任务数,这样的设计目的在于满足多任务的需要。
相同架构下,CPU性能由频率和缓存共同决定。缓存的作用是提供运行所需数据。
cpu 主频、死循环
主频 = 3GHZ,无任何延时的情况下,等价于一秒内会执行30亿次指令
延时存在的情况下,指令次数可能降低到1000次,具体看 python 程序实例
import time def main(): while True: print 1 if __name__ == '__main__': main() // cpu占用20%
import time def main(): while True: print 1 time.sleep(1) if __name__ == '__main__': main() // cpu占用1%
以当前硬件状况来看,大多数设备都是多核机器,即使我们在程序中书写 while(true) 这样的循环也可能只占用 20% 的 cpu
动态磁盘
计算机硬盘类型分为 "基本磁盘" 和 "动态磁盘" 基本磁盘的局限: 1)盘符局限于 C-Z 24种可能 2)某分区扩展只能从相邻的未分配空间拓展 动态磁盘不受这些限制,以动态卷为单位
计算机unicode
计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码
XOR 的神奇特性
txt ^ key = cipher => 加密 cipher ^ key = txt => 解密
邮件
邮件通常包括三种协议,邮件转发协议SMTP,邮件服务器使用该协议接收、转发用户、其他邮件服务器提交的邮件。邮件接收协议POP3,IMAP,POP3是历史上第一个离线邮件协议,用于客户端接收、下载邮件。IMAP同样也也是一种邮件接收协议,它与POP3的区别是IMAP客户端对应的邮件操作(删除...)会反应到邮件服务器上。 邮件通常采用base64编码,邮件使用MIME格式弥补了SMTP只能处理7位ASCII码的缺陷,它将所有非ASCII码的字符通过MIME转为7位ASCII,到达邮件接收服务器之后再还原。
163
服务器名称
服务器地址
SSL协议端口号
非SSL协议端口号
IMAP
993
143
SMTP
465/994
25
POP3
995
110
telnet 发送邮件
使用telnet SMTP地址 端口连接 发送HELO 邮箱服务器名称 发送AUTH LOGIN进行登陆,第一次输入的是base64加密过的用户名,第二次是base64加密过的密码 发送MAIL FROM: <xxx@xx.com>准备发邮件,注意:和<>之间无空格 发送RCPT TO: <xx@xx.com>指定目标邮箱地址,如果目标邮箱地址不存在输出550错误号 发送DATA开始输入邮件内容,一行用.结束。 发送QUIT退出
telnet 接收邮件
使用telnet POP3地址 端口连接 发送USER 用户名进行登陆 发送PASS 密码确定登陆 发送LIST查看邮件列表 发送RETR 编号查看邮件信息 发送DELE 编号删除邮件 发送QUIT退出 针对SSL协议的端口需要使用openssl: openssl s_client -connect pop.gmail.com:995 -quiet
邮件通用格式
Received:from mail139@139.com (unknown[172.16.202.6]) by rmoda-17132 (RichMail) with ODA id 42ec5409b9d04b8-050cc; Fri, 05 Sep 2014 21:25:36 +0800 (CST) X-RM-TRANSID:42ec5409b9d04b8-050cc From: =?gb2312?B?1tC5+tLGtq8xMznTys/k?= <mail139@139.com> Message-ID: <744425079.27371409923191498.JavaMail.hadoop@q201-o06-9> Subject: =?GB2312?B?1tC5+tLGtq/M4dDRo7rH68T6udjXorG+u/q6xQ==?= =?GB2312?B?wuu1scewu7C30dPgtu6jrM/qx+nH67Xju/ey6b+0?= MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_2737_1393666244.1409923191496" X-RICHINFO:CATEGORY:4326;PRODUCTOPERATIONMAIL:2001;SELFCLOSED:1;M:;TEMPLATELIST:2_4;MAILORDERID:141956;NOTIFYTYPE:14;ISMULTITEMPLATE:1;BUSSINESSID:1443;MJ:0;ISWAPNOTIFY:0;CHANNEL:30 X-TDZXINFO: ODACHANNEL:30;ODACATEGORY:4326 X-OP_RICHINFO_MAILTYPE:0 Date: To:netcan ------=_Part_2737_1393666244.1409923191496 Content-Type: text/plain;charset="gbk" Content-Transfer-Encoding: base64 oaHX8L60tcS/zbuno7pbsunT4LbuXWh0dHA6Ly93YXBtYWlsLjEwMDg2LmNuL2ahoQqhoczh0NHE +qO6yta7+sno1sNDTVdBUL3TyOuju8H3wb+wtNbQufrSxravR1BSU7Hq17y8xsvjoaMKCQkJCQkJ CQkKCQkJCQkJCQkKCQkJCQkJCQkKCQkJCQkJCQkKCQkJCQkJCQkKCQkJCQkJICAJIAkgCgkJCgkJ CQkJCQkJCgkJCQkJCgkJCQkJCQkJCiAJCQkJCQkgICAJIAogICAgICAgICAJCQo= ------=_Part_2737_1393666244.1409923191496 Content-Type: text/html;charset="gbk" Content-Transfer-Encoding: base64 PGh0bWw+PGhlYWQ+PHRpdGxlPqGhPC90aXRsZT48bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5 cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD1nYjIzMTIiLz48L2hlYWQ+PGJvZHkgYmdj b2xvcj0iI0ZGRkZGRiIgbGVmdG1hcmdpbj0iMCIgdG9wbWFyZ2luPSIwIiBtYXJnaW53aWR0aD0i MCIgbWFyZ2luaGVpZ2h0PSIwIj48c3BhbiBzdHlsZT0iIGZvbnQ6MHB4LzBweCAny87M5Sc7IGRp c3BsYXk6bm9uZTsiPtfwvrS1xL/Nu6ejuluy6dPgtu5dPGEgaHJlZj0iaHR0cDovL3dhcG1haWwu MTAwODYuY24vZiIgdGFyZ2V0PSJfYmxhbmsiPmh0dHA6Ly93YXBtYWlsLjEwMDg2LmNuL2ahoTwv YT48YnIvPqGhzOHQ0cT6o7rK1rv6yejWw0NNV0FQvdPI66O7wffBv7C01tC5+tLGtq9HUFJTserX vLzGy+Ohozxici8+PC9zcGFuPjx0YWJsZSB3aWR0aD0iNzgwIiBib3JkZXI9IjAiIGFsaWduPSJj ZW50ZXIiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgaWQ9Il9fMDEiIHN0eWxlPSJi b3JkZXItY29sbGFwc2U6Y29sbGFwc2U7IHdpZHRoOjc4MHB4OyBib3JkZXItc3BhY2luZzowO3Bh ZGRpbmc6MDsgbWFyZ2luOjAgYXV0bzsiPjx0cj48dGQ+CQkJPGltZyBzcmM9Imh0dHA6Ly9mdW4u bWFpbC4xMDA4Ni5jbi9jbi8xNDA3LzA4MjIvaW1hZ2VzL2luZGV4XzAxLmpwZyIgd2lkdGg9Ijc4 MCIgaGVpZ2h0PSI4OCIgYWx0PSIiIGJvcmRlcj0iMCIgc3R5bGU9ImRpc3BsYXk6YmxvY2s7Ii8+ PC90ZD4JPC90cj48dHI+PHRkPgkJCTxpbWcgc3JjPSJodHRwOi8vZnVuLm1haWwuMTAwODYuY24v Y24vMTQwNy8wODIyL2ltYWdlcy9pbmRleF8wMi5qcGciIHdpZHRoPSI3ODAiIGhlaWdodD0iMTA3 IiBhbHQ9IiIgYm9yZGVyPSIwIiBzdHlsZT0iZGlzcGxheTpibG9jazsiLz48L3RkPgk8L3RyPjx0 cj48dGQ+CQkJPGltZyBzcmM9Imh0dHA6Ly9mdW4ubWFpbC4xMDA4Ni5jbi9jbi8xNDA3LzA4MjIv aW1hZ2VzL2luZGV4XzAzLmpwZyIgd2lkdGg9Ijc4MCIgaGVpZ2h0PSI4MiIgYWx0PSIiIGJvcmRl cj0iMCIgc3R5bGU9ImRpc3BsYXk6YmxvY2s7Ii8+PC90ZD4JPC90cj48dHI+PHRkPgkJCTxpbWcg ------=_Part_2737_1393666244.1409923191496-- .
无线频段Channel
信道也称频段(Channel),其是以无线信号作为传输媒体的数据信号传送通道。无线宽带路由器可在许多信道上工作,位于临近范围内的无线网络设备须位于不同信道上,否则会产生信号干扰。如果仅有一个无线设备,那么默认信道值6是最为合适的。除非已经有很多无线设备 工作在此信道。 802.11g 、802.11b无线标准有11条信道,但只有3条是非重叠信道(信道1、信道6、信道11)。
基础类型共用地址
通常在各大语言中,当我们声明定义两个具有相同值的变量,它们会公用一块内存。具体动作为:当我们声明并给变量赋值时,编译器会先查找是否已经有某个变量赋为该值,若有则与其公用一块地址,若无则新开一块内存空间存放该值。而当我们删除一个变量时,改值因为没有变量指向它则会被GC回收。
IO
实际上,IO所需要的CPU资源非常少。它的大部分工作都是分派给DMA完成的。即 Direct Memory Access 芯片。
CPU计算文件地址 => 委派DMA读取文件 => DMA接管总线 => CPU的A进程阻塞,挂起 => CPU切换到B进程 => DMA读完文件后通知CPU(中断异常) => CPU切换
cpu位数的意义
CPU的位数代表CPU在同一时间能处理的二进制位数
大端小端
计算机硬件有两种存储数据的方式,大端字节序和小端字节序。其中大端是为了方便人类的阅读,因为人类习惯从高位读起。而计算机为了计算则必须从低位开始读。例如对于一个8位CPU的计算机,数值0x2211,若按照大端存储则为22 11,CPU第一次计算读取到22,第二次计算读取到11。而如果按照小段存储则为11 22,CPU第一次计算读取到11,第二次计算读取到22。 小端对加法友好,大端对除法友好 简单来说,当计算机处理数据时有两种方式,一种是正向读,每次处理CPU位数的数据,这种方式称为大端。另一种是反向读,每次处理CPU位数的数据,这种方式称为小端。 Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。 如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。 下面,举一个实例。 打开"记事本"程序notepad.exe,新建一个文本文件,内容就是一个严字,依次采用ANSI,Unicode,Unicode big endian和UTF-8编码方式保存。 然后,用文本编辑软件UltraEdit 中的"十六进制功能",观察该文件的内部编码方式。 1)ANSI:文件的编码就是两个字节D1 CF,这正是严的 GB2312 编码,这也暗示 GB2312 是采用大头方式存储的。 2)Unicode:编码是四个字节FF FE 25 4E,其中FF FE表明是小头方式存储,真正的编码是4E25。 3)Unicode big endian:编码是四个字节FE FF 4E 25,其中FE FF表明是大头方式存储。 4)UTF-8:编码是六个字节EF BB BF E4 B8 A5,前三个字节EF BB BF表示这是UTF-8编码,后三个E4B8A5就是严的具体编码,它的存储顺序与编码顺序是一致的。
补码的存在意义
补码的存在意义是只用一套电路完成加、减法。 补码计算规则:先去反再加一 注意:取反时符号位不动
5 => 0b0101 2 => 0b0010 -2 => 0b1010 // 如果没有补码 0101 + 1010 1111 == 15,显然错误 // 补码 0101 + 1110 10011 去除溢出位刚好为3
URL编码
目前只有字母 a-zA-Z,数字 0-9,特殊符号 $-_.+!*'(),,以及一些保留字可以不经过编码直接用于URL,但是URL的编码方式相当混乱,需要分情况考虑:
1)当输入网址路径中包含汉字,例如"http://zh.wikipedia.org/wiki/春节",会被转换为"http://zh.wikipedia.org/wiki/春节 "而其实春节的UTF8编码则为E698A5E88A82,所以实际上是采用了UTF8编码然后用相同个数的%连接
2)当查询字符串包含汉字,例如"http://www.baidu.com/s?wd=春节",会被转换为"http://www.baidu.com/s?wd=����",而春节的GB2312编码刚好为B4BABDDA,所以实际上是采用了GB2312编码,为什么突然会采用GB2312编码?主要原因是它是操作系统默认编码,所以当查询字符串是中文时,采用操作系统默认编码
3)由GET和POST请求生成的URL,这时的编码方式由网页的编码决定<meta http-equiv="Content-Type" content="text/html;charset=xxxx">,例如百度采用GB2312,谷歌则采用UTF8
JavaScript中的处理方式
1)escape() => 对除ASCII字母、数字、标点符号 @*_+-./ 以外,对其他所有字符进行unicode编码,'\u0000'到'\u00ff'之间的字符会被转换为%xx的形式,而其他则会被转换为%uxxxx的形式。对应的解码函数为unescape()。
2)encodeURI() => 按照utf8进行编码并在每个字节前面加上%,但是不处理 ;/?:@&=+$,#,对应的解码函数为decodeURI()
3)encodeURIComponent() => 与 encodeURI 唯一的区别是也会对 ;/?:@&=+$,# 编码
BIG5 => 繁体中文 GB2312 => 简体中文
Unicode符号范围 | UTF-8编码方式 (十六进制) | (二进制) ----------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 与 Asciii 兼容 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
该编码方式中前缀 0, 110, 1110, 11110 主要用于“即时解码”,即收到数据不需要等待某个特征符号到来就能直接开始解码。 该前缀中 1 的数目对应字节数,而其他字节中的 10 用于分块传输时判断该字节是否是一个 unicode 符号的开始或者属于前面某个 Unicode 符号。
Unicode 实际上只规定了符号对应的数字序号,而 UTF-8 则是该数字的其中一种编码方式。 以下为从 Unicode 序号编码为 UTF-8 的一个实例。
U+4E3E This fits in the 0x00000800 - 0x0000FFFF range (0x4E3E < 0xFFFF), so the representation will be of the form: 1110xxxx 10xxxxxx 10xxxxxx 0x4E3E is 100111000111110b. Drop the bits into the x above (start from the right, we'll fill in missing bits at the start with 0): 1110x100 10111000 10111110 There is an x spot left over at the start, fill it in with 0: 11100100 10111000 10111110 Convert from bits to hex: 0xE4 0xB8 0xBE
EOF到底是什么
c语言中,EOF是一个常量(-1),当系统读取文件时会对比文件大小和已经读取字节数,相等时返回信号EOF即-1 GO语言中,EOF同样是个常量-1
monospace
monospace是一种等宽度字体,因为当前不论是 windows 的 cmd 还是 linux 的 shell 默认宽度都是每行 80 个字符,使用等宽字体能够很好的显示。
位数截取
x & 0xffffffff // 取最后32位
判断奇偶的高效方法
if (n & 1 != 1) { //奇数 }
模幂运算原理
(a*b)%p == (a%p*b%p)%p // *运算符的优先级高于%,则对于任意 a^b%p都可以初始化结果r=1,然后不断将r*a%p,b次计算之后则位结果 (a^b)%p == 1(*a%p)(*a%p)....(*a%p) |<---------b--------->| /** * 但是当b过大时这种方法非常的慢,因此我们需要使用一个简单的定理: * N为偶数时,x^N = x^2^[N/2] * N为奇数时,x^N = x*x^2^[N/2] */
字节序
本机操作系统的字节序为大端,也就是例如对于 0xaecd9fbd 这样,在内存中将会仍然是 0xaecd9fbd,如果时小端,那么在内存中会把低位置前,将会变成 0xbd9fcdae
简单来说对于 0xaecd9fbd 这样一个序列,高位肯定是最前面的ae,但是计算机读取时不管,计算机读取时只看自己是大端还是小端序,如果是小端序就倒着读。这样才能保证最低位在最前面。
2038年问题
2038年问题2038年1月19日3时14分07秒,32位系统的UNIX时间将会被重置。原因是现今很大一部分Unix系统都是32位的,即使用int32表示时间戳,而int32得最大值为2147483647,那么这个最大值能表示的年数为 2147483647/365/24/60/60 = 68.09,约为68年,Unix时间戳从1970年开始计算,那么到2038年刚好就是68年,int32溢出,时间戳会被重置,即 (0xffffffff + 1) mod (1<<32) = 0
如何快速判断一个数是否是2的幂次
if n & (n-1) == 0 { //ok }
位运算
性质
1. 负数在计算机中都以补码形式存放,即取反(符号位不变)然后加一 2. 补码的补码即原码 3. 任何数字与0异或都不变,与相同位数且所有位数均为1异或则相当于取反 4. 异或满足交换律 => 可用于求数组中只出现一次的数字 5. 任意数字与其本身异或均为0 6. 左移均补0,右移则是视符号为而定,符号位为0则补0,符号位为1则补1
应用
数组中仅有成对的数字,但是不小心丢失了一个数字,如何快速找到这个数字? 答案:将该数组逐个异或,最后的结果即是这个数字。
px 和 pt 的区别
字体大小的设置单位,常用的有2种:px、pt。这两个有什么区别呢?
先搞清基本概念:px就是表示pixel,像素,是屏幕上显示数据的最基本的点;
pt就是point,是印刷行业常用单位,等于1/72英寸。
这样很明白,px是一个点,它不是自然界的长度单位,谁能说出一个“点”有多长多大么?可以画的很小,也可以很大。如果点很小,那画面就清晰,我们称它为“分辨率高”,反之,就是“分辨率低”。所以,“点”的大小是会“变”的,也称为“相对长度”。
pt全称为point,但中文不叫“点”,查金山词霸可以看到,确切的说法是一个专用的印刷单位“磅”,大小为1/72英寸。所以它是一个自然界标准的长度单位,也称为“绝对长度”。
因此就有这样的说法,pixel是相对大小,而point是绝对大小。
分清“屏幕效果”和“打印效果”:
在浏览网页过程中,所有的“大”“小”概念,都是基于“屏幕”这个“界面”上。“屏幕”上的各种信息,包括文字、图片、表格等等,都会随屏幕的分辨率变化而变化,一个100px宽度大小的图片,在800×600分辨率下,要占屏幕宽度的1/8,但在1024×768下,则只占约1/10。所以如果在定义字体大小时,使用px作为单位,那一旦用户改变显示器分辨率从800到1024,用户实际看到的文字就要变“小”(自然长度单位),甚至会看不清,影响浏览。
那是不是用pt做单位就没这样的问题呢?错!问题同样出现。刚才的例子已经很清楚的说明,在不同分辨率下,无论是px还是pt,都会改变大小。以现在的电脑屏幕情况,还没有一种单位可以保证,在不同分辨率下,一个文字大小可以“固定不变”。因为这很难以实现也不是很有必要:全球电脑用户以亿来数,屏幕从14寸到40寸甚至更高都有,屏幕大小不同,分辨率也不同,要保证一个字体在所有用户面前大小一样,实在是MISSION IMPOSSIBLE。另外,电脑有其自身的调节性。
那在页面设计中到底是用px还是pt呢?
我认为,这个并没有什么原则性差异,就看自己处于什么角度思考了。
Mac机怎么情况不清楚,在Windows里,默认的显示设置中,把文字定义为96DPI(PPI,微软都将DPI和PPI混为一体,我们也就无须较真了)。这样的定义,说明了:1px=1/96英寸。联系pt的概念,1pt=1/72英寸,可以得出,在这样的设置中,1px=0.75pt,常见的宋体9pt=12px。在显示器分辨率不变的基础上(比如现在常用的1024×768),1px大小也就固定不变,改变显示设置,调整为144DPI,可以得出,1px=0.5pt,常见的宋体9pt=18px。原先用12px来组成的一个文字,现在需要18px来组成,px多了,文字就“大”了,更易阅读了。
所以,px和pt的使用区别,只有当用户改变默认的96DPI下才会产生:使用px定义文字,无论用户怎么设置,都不会改变大小;使用pt定义文字,当用户设置超过96DPI的值,数值越大,字体就越大。
(附公式:px = pt * DPI / 72) 对了,刚才还提到改变浏览器中文字大小的选项,也可以改变网页的文字大小。但在这种情况下,使用px和pt都是无效的,因为这2个都是有实际“pixel”数值的单位,比如9pt是12px,大小固定。这里要引用新的单位:em,其实就是%。因为当网页中的字体没有给出实际的px或pt定义的话,会有一个默认值:12pt即16px,对应浏览器中“字体大小”中的“中等”,以这个为标准,变大或缩小。(只适用于IE,在FF中,即便定义px或pt也都可以变大变小)
所以,从这个概念上看,em才是真正的“相对单位”(百分比嘛,当然是相对),而px和pt都是绝对单位(都有固定值)。
在网页设计中,面向用户的屏幕的基本单位是px,因此使用px作为单位是最简单也最容易理解的,而pt也不过是通过了Windows的设置乘上了一个比率转变成px再显示,算是绕了个圈子。参考大部分大型网站,包括Adobe和Microsoft,都是使用px作为单位,而且在HTML中,默认的单位就是px,是不是也暗示着px是网页设计的“内定单位”?
但在Word或Photoshop中,使用pt就相当方便。因为使用Word和Photoshop的主要目的都不是为了屏幕浏览,而是输出打印。当打印到实体时,pt作为一个自然长度单位就方便实用了:比如Word中普通的文档都用“宋体 9pt”,标题用“黑体 16pt”等等,无论电脑怎么设置,打印出来永远就是这么大。又或者在Photoshop中,设置一个图片中的某个艺术效果的字体是72pt大小,然后分别将这张图片设为300DPI和72DPI,再打印出来,就可以看出,这2个字体大小完全一样,只是“清晰度”不同,300DPI更清晰。这是毫无疑问的结果。
最后整理一下所有出现过的单位:
px:pixel,像素,屏幕上显示的最小单位,用于网页设计,直观方便;
pt:point,是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用;
em:即%,在CSS中,1em=100%,是一个比率,结合CSS继承关系使用,具有灵活性。
PPI(DPI):pixel(dot)per inch,每英寸的像素(点)数,是一个率,表示了“清晰度”,“精度”
个人总结: px 和 pt 和 em:  - pt是绝对单位,72英寸分之一  - px是相对单位,计算px的绝对长度需要视DPI而定,在DPI为96的情况下,也就是没英寸96个像素点时,px/pt=3/4
  • DPI可以衡量显示精度,其代表每英寸的像素点的数量
  • em是相对单位,1em代表其大小等于当前文本大小
通常word类的软件会直接使用pt,因为这样不管如何设置桌面分辨率,始终字体,页面尺寸都是绝对长度,打印出来都相同。 而如果一些软件通过px衡量大小,那么当增大桌面分辨率的时候,软件字体,尺寸就会有所改变
在网页设计中如果需要使用em,最好在body中设置,font-size=62.5%,原因是浏览器会默认字体大小为16px,这样就使得1em等于10px,如果需要 改写网页就非常简单了,原尺寸为16px的话,就设置1.6em,但是em因为会继承父级元素尺寸而非常的麻烦,比如在.container中设置字体为1.6em, 那么在子元素中字体大小就是相对于父级.container元素,也就是我们需要设置1em代表16px。
为了解决这个问题css3引入了rem: 它的好处是,其只相对于html根元素改变。通常设置: html {font-size: 62.5%}
短网址服务的原理
短网址(Short URL),顾名思义就是在形式上比较短的网址。通常用的是asp或者php转向,在Web 2.0的今天,不得不说,这是一个潮流。 目前已经有许多类似服务,借助短网址您可以用简短的网址替代原来冗长的网址,让使用者可以更容易的分享链接。例如:http://t.cn/SzjPjA
其中一种算法:
1)将长网址md5生成128位的16进制签名串,分为4段, 每段4个字节; 2)对这四段循环处理, 取这一段对应的4个字节, 将他看成16进制串与0x3fffffff(30位1)与操作, 即超过30位的忽略处理; 3)这30位分成6段, 每5位的数字作为字母表的索引取得特定字符, 依次进行获得6个字符; 4)总的md5串可以获得4个含有6个字符的字符串; 取里面的任意一个就可作为这个长url的短url地址;
浏览器重定向
浏览器会在收到 301 和 302 状态码时自动跳转,其区别为:
301 : 永久重定向 302 : 暂时重定向
>>> 和 >> 的区别
两者都表示移位操作,但是 >> 表示算术移位,带符号,>>> 表示逻辑移位,无符号
根据符号位决定补0还是补1总是补0
例如:
  • 2 的二进制表示为 11111110 (补码)
  • 2 >>> 1 == 0b01111111 -2 >> 1 == 0b11111111
理解 Tcp Keep-Alive
场景:A和B通过三次握手建立好TCP连接,突然间B宕机,如果A和B一直没有数据通讯的需求,A就永远不能发现B宕机,导致资源的浪费。
于是引入了 keepalive 机制,a会定期给b发送空的数据包,通俗讲就是心跳包,一旦发现到b的网络不通就断开连接。
如何告诉服务器使用长链接:
Connection: Keep-Alive
Linux内核对于tcp keepalive的调整主要有以下三个参数
1. tcp_keepalive_time : 超时时间 2. tcp_keepalive_intvl : 间隔 3. tcp_keepalive_probes : 关闭连接前的心跳包个数
查看这三个参数
$ cat /proc/sys/net/ipv4/tcp_keepalive_time 7200 $ cat /proc/sys/net/ipv4/tcp_keepalive_intvl 75 $ cat /proc/sys/net/ipv4/tcp_keepalive_probes 9 即当 tcp 发现有 tcp_keepalive_time(7200) 秒未收到对端数据后,开始以间隔 tcp_keepalive_intvl(75) 秒 的频率发送的空心跳包,如果连续 tcp_keepalive_probes(9) 次以上未响应代码对端已经 down 了,close连接
Keep-Alive 优缺点
根据 RFC2616 定义,单个客户端不允许开启两个以上的长连接,这个标准的目的是减少HTTP响应的时间,减少网络阻塞。
优点
1. 普通用户体验提升,例如频繁的访问某个网站只需第一次建立TCP连接 2. 克服 TCP slow-start 问题
缺点
1. 超时时间设置不当容易损害服务器整体性能,直接影响到服务器的并发数
内存墙
内存墙,指的是内存性能严重限制CPU性能发挥的现象。内存的性能指标主要有“带宽”(Bandwidth)和“等待时间”(Latency)。
过去的20多年中,处理器的性能以每年大约55%速度快速提升,而内存性能的提升速度则只有每年10%左右。长期累积下来,不均衡的发展速度造成了当前内存的存取速度严重滞后于处理器的计算速度,内存瓶颈导致高性能处理器难以发挥出应有的功效,这对日益增长的高性能计算(High Performance Computing,HPC)形成了极大的制约。
当处理器厂商意识到单纯依靠提高处理器频率并不能持续提升计算性能时,便把目光转向了利用多核心并行计算技术来提升计算性能,同时也希望该技术能缓解内存瓶颈。 但处理器核心越多,性能就越高吗?实际情况并没有那么简单,除了如何有效地给多核心分配任务这一难题之外(核心越多,任务分配的难度越大),多核心并行计算还遭遇到了更为严重的“内存墙”问题。这是因为在高度并行的处理方式下,多核心共享有限的内存带宽将会造成更大的延迟,就好像一条高速公路只有4条道,却有4辆以上的车要并列行驶,当然会造成道路拥堵、行驶缓慢了。 美国桑迪亚国家实验室(Sandia National Laboratories,SNL)所进行的一项多核处理器性能仿真测试也正好验证了上述问题,SNL研究人员在一篇题为《多核对超级计算机是一个坏消息》的文章中指出:在信息科学领域,更多核心的处理器并不一定会带来更高的处理性能。SNL的仿真测试结果表明:由于“内存墙”的制约,超过8核心之后,处理器性能几乎没有提升,而16核处理器的性能甚至不升反降。由此可见,随着处理器核心的不断增多、处理性能的不断提升,“内存墙”产生的瓶颈效应对基于多核处理器的高性能计算的制约将日趋严重。
链接:内存墙
动静态作用域
大部分语言采取静态作用域,bash采用动态作用域,他们的区别是在函数执行时如果在函数内部未找到变量,应该是去函数定义时所处的作用域找还是在函数执行时 所处的作用域查找。
静态 === 词法,静态作用域又被称为词法作用域
在全局作用域中“定义”一个函数到时候,只会创建包含全局作用域的作用域链。 只有“执行”该函数的时候,才会复制创建时的作用域,并将当前函数的局部作用域放在作用域链的顶端。
和大多数的现代化编程语言一样,JavaScript是采用词法作用域的,这就意味着函数的执行依赖于函数定义的时候所产生(而不是函数调用的时候产生的)的变量作用域。为了去实现这种词法作用域,JavaScript函数对象的内部状态不仅包含函数逻辑的代码,除此之外还包含当前作用域链的引用。函数对象可以通过这个作用域链相互关联起来,如此,函数体内部的变量都可以保存在函数的作用域内,这在计算机的文献中被称之为闭包。
从技术的角度去将,所有的JavaScript函数都是闭包:他们都是对象,他们都有一个关联到他们的作用域链。绝大多数函数在调用的时候使用的作用域链和他们在定义的时候的作用域链是相同的,但是这并不影响闭包。当调用函数的时候闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链的时候,闭包become interesting。这种interesting的事情往往发生在这样的情况下: 当一个函数嵌套了另外的一个函数,外部的函数将内部嵌套的这个函数作为对象返回。一大批强大的编程技术都利用了这类嵌套的函数闭包,当然,javascript也是这样。可能你第一次碰见闭包觉得比较难以理解,但是去明白闭包然后去非常自如的使用它是非常重要的。
通俗点说,在程序语言范畴内的闭包是指函数把其的变量作用域也包含在这个函数的作用域内,形成一个所谓的“闭包”,这样的话外部的函数就无法去访问内部变量。所以按照第二段所说的,严格意义上所有的函数都是闭包。
需要注意的是:我们常常所说的闭包指的是让外部函数访问到内部的变量,也就是说,按照一般的做法,是使内部函数返回一个函数,然后操作其中的变量。这样做的话一是可以读取函数内部的变量,二是可以让这些变量的值始终保存在内存中。
HTTP2 HPACK头压缩
HPACK 提供了一个静态和动态的 table,静态 table 定义了通用的 HTTP header fields,譬如 method,path 等。发送请求的时候,只要指定 field 在静态 table 里面的索引,双方就知道要发送的 field 是什么了。
对于动态 table,初始化为空,如果两边交互之后,发现有新的 field,就添加到动态 table 上面,这样后面的请求就可以跟静态 table 一样,只需要带上相关的 index 就可以了。
SSD和DRAM的区别
  1. SSD是non-volatile, DRAM是volatile断电即丢失数据
  1. DRAM随机访问的速度快, SSD顺序访问的数据快
  1. SSD因为使用了闪存技术, 不需要像机械硬盘一样寻道, 所以随机访问也很快. 但是SSD的顺序访问仍然比随机访问快
  1. DRAM是byte寻址, SSD是block寻址
  1. DRAM大概比SSD快15倍, SSD比HDD快100倍, 所以DRAM大概比HDD快1000-10000倍
DRAM和SRAM的区别
  1. SRAM大概比DRAM快10倍
虚拟内存的作用
  1. swap-out不常用的数据到disk, swap-in需要用到的数据. 作为缓存使用
  1. 简化不同程序的内存管理, 给每个进程提供了一致的、完整的地址空间
  1. 不用担心一个程序的误操作影响到其他程序, 隔离寻址空间
  1. 用户进程无法访问privileged内核进程的数据
  1. MMU作为不同程序内存管理的枢纽
  1. 结合swap给进程提供了一个更大的内存空间
  1. 块是相对于文件而言, 页是相对于内存而言, 他们大小可能都为4KB左右
  1. 简化程序链接(link)和加载(load)
  • CPU缓存块 64B 左右, DRAM内存块 4KB 左右, x86系统的内存块大概是 4MB
固态硬盘为什么短命?
  1. 无法像机械硬盘一样直接覆盖数据, 需要先”擦除”, 再”写入”
页到底指什么?
  1. CS中的页有三种, Hardware Page, Os Page, Database Page