大话编程
摘录:
所谓编程,就是把自然语言的需求翻译成计算机语言, 让计算机去执行。 对于刚入行的人, 理解CPU和内存是怎么在一起工作的, 绝对是基础中的基础。
如果我们简化一下, CPU和内存其实特别简单,内存就是一个个的小格子, 每个格子都有一个编号, 格子中的数据可以被CPU所读写。
CPU 内部的构造超级复杂, 但我们这次只关注两个东西:
一是运算器,可以做各种运算, 但是有个限制,这个运算器不能直接操作内存进行运算, 他在运算时使用的是内部的数据格子(学名叫寄存器), 为了区分开, 我把他们叫做R1,R2,R3,R4,假设只有这么4个, 统称Rx。
CPU必须把数据装载到寄存器中才能运算。
CPU运行速度快的令人发指, 但是它能做的事情却简单的令人发指, 主要是以下四种:
(1) 从内存的某个格子中读取数据放入自己内部的寄存器Rx
(2) 把Rx的数据写入内存的某个格子中(会把原有数据覆盖)
(3) 进行数学运算和逻辑运算
(4) 根据条件进行跳转
数学运算就是加减乘除, 逻辑运算就是AND , OR 这样的基本运算,没接触过的暂时可以不用深究。
根据条件进行跳转就是从一个指令跳转到另外一个指令。
切记切记: 内存只是一个个可以读写的格子, CPU简单到只能做上面描述的4件事。
因为CPU不能直接操作内存进行运算, 需要把数据从内存和CPU之间搬来搬去。
还有一个问题,CPU在运行的时候,从哪里取获得那些指令?
估计你已经想到了, 对,就是内存 ,指令也需要在内存中才能够被CPU访问到, CPU从内存读到指令以后,会进行分析(译码) , 看看这个指令是干什么的, 然后再进行运算。
所以我们的内存小格子中不仅仅存放的是数据,还存放着至关重要的程序指令! 我们需要告诉CPU第一条指令在什么地方, 然后CPU就可以疯狂的开始运行了:
这些指令在内存中肯定不是我们看到的自然语言, 而是二进制的表示。
那内存的数据又是从哪里来的? 肯定是硬盘了, 我们写好的程序会放在硬盘上, 在运行的时候才调入内存。
小白科普:从输入网址到最后浏览器呈现页面内容,中间发生了什么?
摘录:
当你在浏览器中输入网址(例如www.coder.com)并且敲了回车以后, 浏览器首先要做的事情就是获得coder.com的IP地址,具体的做法就是发送一个UDP的包给DNS服务器,DNS服务器会返回coder.com的IP, 这时候浏览器通常会把IP地址给缓存起来,这样下次访问就会加快。
比如Chrome, 你可以通过chrome://net-internals/#dns来查看。
有了服务器的IP, 浏览器就要可以发起HTTP请求了,但是HTTP Request/Response必须在TCP这个“虚拟的连接”上来发送和接收。
想要建立“虚拟的”TCP连接,TCP邮差需要知道4个东西:(本机IP, 本机端口,服务器IP, 服务器端口),现在只知道了本机IP,服务器IP, 两个端口怎么办?
本机端口很简单,操作系统可以给浏览器随机分配一个, 服务器端口更简单,用的是一个“众所周知”的端口,HTTP服务就是80, 我们直接告诉TCP邮差就行。
经过三次握手以后,客户端和服务器端的TCP连接就建立起来了! 终于可以发送HTTP请求了。
之所以把TCP连接画成虚线,是因为这个连接是虚拟的, 详情可参见之前的文章《TCP/IP之大明邮差》,《张大胖的Socket》
一个HTTP GET请求经过千山万水,历经多个路由器的转发,终于到达服务器端(HTTP数据包可能被下层进行分片传输,略去不表)。
Web服务器需要着手处理了,它有三种方式来处理:
(1) 可以用一个线程来处理所有请求,同一时刻只能处理一个,这种结构易于实现,但是这样会造成严重的性能问题。
(2) 可以为每个请求分配一个进程/线程,但是当连接太多的时候,服务器端的进程/线程会耗费大量内存资源,进程/线程的切换也会让CPU不堪重负。
(3) 复用I/O的方式,很多Web服务器都采用了复用结构,例如通过epoll的方式监视所有的连接,当连接的状态发生变化(如有数据可读), 才用一个进程/线程对那个连接进行处理,处理完以后继续监视,等待下次状态变化。 用这种方式可以用少量的进程/线程应对成千上万的连接请求。
(码农翻身注:详情参见《Http Server:一个差生的逆袭》)
我们使用Nginx这个非常流行的Web服务器来继续下面的故事。
对于HTTP GET请求,Nginx利用epoll的方式给读取了出来, Nginx接下来要判断,这是个静态的请求还是个动态的请求啊?
如果是静态的请求(HTML文件,JavaScript文件,CSS文件,图片等),也许自己就能搞定了(当然依赖于Nginx配置,可能转发到别的缓存服务器去),读取本机硬盘上的相关文件,直接返回。
如果是动态的请求,需要后端服务器(如Tomcat)处理以后才能返回,那就需要向Tomcat转发,如果后端的Tomcat还不止一个,那就需要按照某种策略选取一个。
编程语言
Node.js :我只需要一个店小二 只用一个线程来处理所有请求,事件驱动编程
程序人生
老司机经验
GitHub/Stackoverflow 找工作时有什么用?
不加断点调试的程序员是好程序员:思考, 不看代码的思考, 是最好的调试方式。
你最爱的Java
闲聊
编程感悟
职场