计算机各部件运行速度和存储器结构,了解计算机系统的各种问题以及相应的解决方案。
两幅图
计算机各部件运行速度
表的第三列将成本转换为我们理解的时间尺度,即秒、分、日、月和年的时间尺度。在这里,操作的成本是按比例缩放的,假设CPU周期的成本是1秒,而不是其他操作的成本。
存储器的层级结构
正是由于计算机各个部件的速度不同,容量不同,价格不同,导致了计算机系统/编程中的各种问题以及相应的解决方案。以下是几个例子
案例
CPU 速度超级快,不能老是让它闲着,要充分压榨它。这里有两个强劲理由
- 人类需要多个程序同时『运行』:CPU 时间分片,各个程序在 CPU 上轮转,造成多个程序同时在运行的假象,即『并发』
- 当 CPU 需要 IO 操作(硬盘、网络)时,不能干等
- 等待的时候,一定要切换,去执行别的程序,程序切换的时候需要保存程序执行的现场,以便以后恢复执行,于是需要一个数据结构来表示,这就是『进程』
- 如果一个进程只有一个执行流,如果进程去等待硬盘操作的时候,那程序就会被阻塞,无法响应用户的输入,所以必须有多个执行流,即『线程』
需要持久化的数据一定要保存到硬盘中,但是硬盘超级慢,支持不了大量的并发访问,那怎么办
- 最长访问的热点数据放到 CPU 缓存中,但 CPU 缓存实在太小,无法满足需求
- 退而求其次,把热点数据放到速度稍慢的内存中,于是就出现了应用程序的缓存
Tomcat 应用服务器,对于每个请求都要用一个线程来处理,如果有一万个请求进来,会创建一万个线程来处理吗
- 显然不会,因为线程多了,开销会很大,线程切换会很慢,因此使用线程池来复用
- 如果线程都因为访问硬盘、数据库或网络调用,导致线程池被耗尽了,怎么办呢
- 仅使用几个线程,比如和 CPU 核心数量一样,遇到 IO 操作,程序就注册一个钩子函数放在那里,线程就去处理别的请求,等到 IO 操作完成了,系统会给这个线程发送一个事件,线程调用之前的钩子函数来处理,这就是『异步,非阻塞』的处理方式,Node.js 和 Vert.x 都采用类似的思想
Redis 使用单线程的方式来处理请求的
- 其面对的是内存,内存速度在计算机体系中仅次于 CPU,因此可以快速的执行内存的读写操作
- 单线程巨大的优势:没有竞争,不需要加锁
来源
码农翻身