堃的网站-计算机科学通识:从硬件到算法
CPU · 内存 · 操作系统 · 编程语言 · 网络 · 数据结构 · 算法思维
🧠 CPU · 计算机的"大脑"到底在做什么
📝 核心概念

CPU(中央处理器)的原理其实简单到令人惊讶
CPU 只会做三件事:读取指令、解码指令、执行指令。它像一个极其勤奋但智商有限的工人——只会加法、比较、跳转、读写内存这些基础操作,但一秒钟能做几十亿次。

你玩的3A游戏、看的4K视频,本质上都是几亿条"把这两个数加起来""判断这个数是不是0""跳到第xxx行"这样的指令堆积而成的。CPU 不懂什么是游戏,它只是忠实地执行每一条机器码。所谓的"智能",是更高层抽象的结果。

💡 深入理解

CPU 类比——乐高积木定律
乐高只有几十种基础砖块,但能搭出任何你想要的形状。CPU 也只有几十种基础指令(比如 x86 架构大约一千多条,RISC-V 甚至只有几十条),却能运行所有软件。这背后的道理是图灵完备:只要一台机器能做条件判断和循环,理论上就能算出任何可计算的问题。所以"简单指令+极快速度"的组合,反而比"复杂指令+慢速"更强大。这也是为什么现在的手机芯片(ARM/RISC-V)反而比老式复杂指令集更高效——大道至简。

💾 内存与存储 · 为什么你的电脑需要快慢搭配
📝 核心概念

存储金字塔:寄存器 > 缓存 > 内存 > 硬盘/SSD
越靠近 CPU,速度越快、容量越小、价格越贵。寄存器的读写速度是纳秒级,容量只有几十个字节;内存是微秒级,容量几十 GB;SSD 是毫秒级,容量 TB 级。这是一个精心设计的折中方案——用最贵的资源放最常用的数据,用便宜的方案放不常用的数据。

内存和硬盘的区别:内存是"工作台",断电就忘;硬盘是"书柜",能永久保存。CPU 不能直接去硬盘拿数据(太慢了),所以操作系统会把要用的数据先搬到内存,CPU 再操作。

💡 深入理解

缓存的哲学:局部性原理
计算机科学里有一个非常优美的发现——局部性原理:如果 CPU 刚刚访问了某个内存地址,那它大概率很快就会再次访问它(时间局部性)或访问它附近的数据(空间局部性)。缓存就是基于这个原理工作的:把最近用过的数据暂时留在离 CPU 最近的地方。这也是为什么遍历数组比遍历链表快——数组在内存里是连续的,完美契合空间局部性,而链表的节点东一个西一个,CPU 的缓存预读根本猜不中。一个好的程序员,会主动让自己的代码"缓存友好"。

🪟 操作系统 · 隐形的总管家
📝 核心概念

操作系统的核心工作就两件事:管理硬件 + 给程序一个假象。
管理硬件:CPU 时间怎么分配?内存谁用哪一块?硬盘文件怎么存?打印机谁先用?
给假象:每个程序都觉得"整个 CPU 都是我的""我有无限内存""硬盘是一个文件夹树"。但实际上 CPU 在疯狂切换、内存被分成了无数页、硬盘可能跨了几块物理磁盘。操作系统用虚拟化技术,让每个程序都活在舒适区里,互不干扰。

进程 vs 线程:进程是一个运行中的程序(有自己的内存空间),线程是进程内部的一条执行流(共享内存)。就像一个工厂(进程)里有多个工人(线程),工人共用厂房设备,但各有各的工作台。

💡 深入理解

调度策略——为什么电脑"卡"了?
如果有人问你"电脑卡了怎么办",你能从调度层面解释:操作系统会给每个进程分配一个时间片(通常几毫秒),进程轮流上 CPU。当某个进程占着 CPU 不放(死循环、密集计算),或者太多进程同时在争抢 I/O 设备(比如都在读硬盘),调度器就会应接不暇。你感觉到的"卡",实际上是你的前台程序(比如浏览器)迟迟排不上 CPU 的号。这也是为什么"关掉后台程序"会有效——不是它们占了内存,而是它们退出了 CPU 的竞争队列。
更深一层,现代操作系统用的是完全公平调度器(CFS),它不是简单的轮转,而是给每个进程算"虚拟运行时间",始终保持一种公平感——即便是 CPU 密集型和 I/O 密集型混在一起,也能各得其所。

📝 编程语言 · 为什么需要"翻译官"
📝 核心概念

计算机只认识机器码(0和1),但人类写 0 和 1 会疯掉。
于是诞生了编译器解释器——它们是把人类可读的代码翻译成机器码的翻译官。

编译型语言(C/C++/Rust/Go):提前把整个程序翻译好,生成一个可执行文件。运行时不再需要翻译,直接跑机器码,速度极快。缺点是每次改代码都要重新编译。就像提前把整本书翻译好了,读者直接看中文版。
解释型语言(Python/JavaScript):运行时一边读代码一边翻译执行,不需要提前编译。改完代码立刻就能跑,开发效率高。缺点是需要一个"翻译官"跟着,速度较慢(但现代有了 JIT 即时编译,差距正在缩小)。就像请了个同声传译,你说一句他翻一句。

💡 深入理解

JIT(即时编译)——鱼与熊掌可以兼得
传统的解释型语言慢,编译型语言不方便。有没有办法两全其美?JIT 的做法很聪明:运行时不是傻傻逐行解释,而是先让程序跑起来——同时偷偷观察哪些代码段被反复执行(热点代码)——然后把这些热点即时编译成机器码。下次再跑到这里,直接上机器码,速度飙升。
这也是为什么 JavaScript(V8引擎)、Java(JVM)、Python(PyPy)都能有不错的性能。V8 引擎甚至有多层 JIT:先用简单的编译器快速生成代码,如果发现某段代码跑得特别频繁,再用优化编译器做深度优化。这就是"先让它跑起来,再让它跑得快"的哲学。

🌐 计算机网络 · 从邮局到 TCP/IP
📝 核心概念

互联网底层最核心的两个协议:IP 和 TCP。
IP(网络层协议):相当于信封上的地址。每台联网设备都有 IP 地址,IP 协议负责把数据包从源地址送到目的地址——但不保证送到、不保证顺序、不保证不重复。它只管"扔出去"。

TCP(传输层协议):相当于挂号信 + 签收确认。它在 IP 之上,确保数据完整、有序、不丢失地到达。发出去一个包,对方要回一个 ACK(确认);没收到 ACK 就重传;到了之后还要按序号排好队。这就是为什么你下载一个文件不会缺斤少两,网页不会只加载一半。

一句话理解:IP 负责"找路",TCP 负责"可靠"。

💡 深入理解

TCP 三次握手——为什么不是两次也不是四次?
建立 TCP 连接需要三次握手,这是一个精妙的稳定性设计。用打电话来比喻:
A:"喂,听得见吗?"(SYN)
B:"听得见,你能听见我吗?"(SYN+ACK)
A:"能听见,开始聊吧。"(ACK)

为什么不是两次?如果只用两次,B 回应了就算连接建立,但 A 可能已经挂了(第一次请求在网络里卡了很久才到,A 早就放弃了),B 却傻等。第三次确认确保了双方都知道对方的"存在"是实时的。
为什么不是四次?因为 B 的 SYN 和 ACK 可以合并为一条消息(piggyback),没必要分开发。三是个最优解——不多不少,刚好在效率和可靠性之间取得平衡。

🏗️ 数据结构 · 把数据放对了,问题就解决了一半
📝 核心概念

为什么学编程要学数据结构?因为不同形状的"容器",适合不同用途。
数组:一排连续的格子,知道第几个就直接跳到对应位置(O(1)访问)。但插入删除要搬家(O(n))。
链表:每个节点记住下一个是谁,像火车车厢。插入删除很方便(O(1)),但找第 100 个节点得从头数(O(n))。
哈希表:用"钥匙"直接算出放在哪个抽屉。查找、插入、删除都是平均 O(1),简直是作弊级性能。代价是抽屉大了浪费空间,抽屉小了容易冲突。
树(尤其是 B+树):分层管理,每层都排好序。数据库索引的核心就是 B+树——为什么几亿条数据里查一条只要几十次磁盘读取?因为树的层数只有 3\~4 层,每层一次 I/O。

💡 深入理解

没有万能的数据结构,只有最配场景的数据结构。
哈希表 O(1) 听着很完美,但它不支持范围查询("找出所有价格在 100 到 200 之间的商品"),也无法有序遍历。B+树支持范围查询,但插入需要维护平衡。红黑树的平衡更严格,查询稳定,但实现复杂。

真正的工程智慧体现在Redis 的数据结构设计:它用跳跃表(Skip List)实现有序集合——跳跃表本质上是给链表加了"高速索引",就像一本书有目录,你不用从头翻到尾。查询复杂度 O(log n),实现却比红黑树简单得多。这就是工程中的实用主义:不追求理论上最优,追求"足够好 + 好维护"。

🔍 算法思维 · 计算机能有多"聪明"
📝 核心概念

算法不是高深的数学,而是一套解决问题的"食谱"。
贪心:每步选看起来最好的,不回头。比如找零钱时优先给大面额。简单高效,但不保证全局最优。
动态规划:把大问题拆成小问题,小问题的结果存起来(记忆化),避免重复计算。比如算斐波那契数列,如果不存结果,算 F(50) 能把 CPU 算冒烟;存了之后秒出。
分治:把问题拆成互不相干的子问题,各自解决后合并。归并排序就是典型——把一个乱序数组不停切成两半,切到底后两两合并,每次合并都是有序的。
二分查找:哲学级的简单。猜 1~100 的数字,每次都猜中间——最多 7 次就能找到。100万个数字里找一个,最多也就 20 次。这背后是对数思维:问题的规模翻倍,需要的步数只增加 1。

💡 深入理解

动态规划的灵魂——"最优子结构"
很多初学者背了动态规划的模板但还是不会做题,根本原因是不理解它真正的前提条件:问题必须具有最优子结构——即全局最优解可以由局部最优解推导出来。

比如"背包问题":一个容量有限的包,每件物品有价值有重量,怎么装总价值最高?暴力枚举是 O(2^n),n 件物品就是 2^n 种组合,40 件物品能算到地老天荒。但动态规划只需要 O(n×W),因为发现了一个规律——"前 i 件物品在容量 j 的包里的最大价值"这个子问题的解,可以被比它更小的子问题推导出来。把这个发现在二维表格里填满,答案就在右下角。

这就是动态规划的核心:不是死记公式,而是找到状态定义和状态转移——一旦发现了"大问题如何由小问题构成",剩下的只是填表。

来 玩 小 游 戏
🎵
是否播放背景音乐?
◢ 俄罗斯方块 ◣
🔷 分数 0
移动端触摸操作区 · 键盘 WASD + 空格
🐍 贪吃蛇 · 经典 🍎
🍎 长度 0
移动端触摸操作区 · 键盘方向键 + P 暂停

主流编程语言对比速查

语言 范式 类型系统 主要用途 代表作

🤖 智能客服

💬 你好!有什么可以帮你的?
🎬 视频播放
0:00 / 0:00