了解“存储程序”思想(常与约翰·冯·诺依曼相关)如何催生可复用软件、通用计算机与现代编程。

现代计算的核心是一个简单的问题:是什么让一台机器能在不重新改造的情况下执行许多不同的任务? 早期电子计算机能很快计算,但“换工作”常常意味着要物理改变机器的设置。存储程序思想是那个转折点,使计算机真正变得可编程。
一个存储程序计算机把任务的指令(程序)存放在与程序处理的数据相同类型的内部内存中。你不需要重接线路或手动重新配置面板;只要把一组新的指令载入内存,就可以运行不同的任务。
现在听起来理所当然,但这是一次深刻的转变:
这不仅仅是历史趣闻。存储程序概念解释了为什么“软件”与“硬件”是两回事,以及为什么今天通过更新设备就能在不更换芯片的情况下解锁新功能。
接下来的章节我们会讲早期计算机面临的问题、存储程序方法改变了什么、阐明这一思想的人与文献(包括著名的 EDVAC 报告),以及“冯·诺依曼架构”如何成为一种被广泛使用的设计名称。
虽然约翰·冯·诺依曼的名字与存储程序计算机紧密相关,但功劳属于更广泛的团队与时代。许多研究者在构建首批实用电子计算机时同时趋向于类似的想法。本文保持这种语境,因为理解团队协作有助于解释这一思想如何迅速传播并成为大多数后续计算机的默认模型。
在存储程序思想出现之前,许多早期计算机并不是像我们现在说的那样“运行软件”。它们可以做高速计算,但告诉它们做什么常常意味着物理改变机器本身的结构。
一种常见做法是使用插板、跳线和开关面板。操作人员会在插座之间连接导线、设置一排排开关,有时还要调整定时单元以确保信号按正确顺序到达。“程序”并不是一个你加载的文件——而是一个临时的接线图。
这种配置能工作,但代价隐性:每个新任务都是一个小型工程项目。如果你想改变操作顺序(加法、乘法、比较、循环),可能要移动几十或几百个连接。一个错位的电缆可能产生难以诊断的错误,因为逻辑分散在硬件连接上,而不是写成可读的步骤。
重新配置可能需要数小时或数天,尤其当机器需要小心断电、重接线路并反复测试时。这导致灵活性受限:这些机器常常长时间安排一种计算,因为切换工作过于破坏性。
想象一台机器被配置来计算炮兵射表——长而重复的计算,公式固定。如果研究人员想让同一台机器解决另一个问题,比如为人口普查汇总统计结果,这并不是“编辑程序然后重跑”。操作顺序、中间存储步骤和条件检查可能完全不同,需要重新设计插板并进行全套验证。
这正是存储程序计算机旨在摆脱的世界。
存储程序计算机是一台将指令(程序)保存在与程序使用的数据相同工作内存中的机器。换句话说,计算机不再把“做什么”与“要处理什么”视为两类不同的东西——二者都作为内存中的比特模式存储。
早期计算机先驱谈到内存时,指的是计算机的快速、可直接使用的内部存储——我们现在最接近称之为 RAM 的东西。它是处理器在运行时可以快速读写的地方。
这不同于像硬盘或 SSD 这样的长期存储。磁盘适合在断电时保存文件,但它不是处理器在运行时频繁读取下一条指令和更新中间结果的即时工作区。
一旦指令被保存在内存中,切换任务就变得极其简单:你可以把一个新程序载入内存并运行它,而无需重建、重接线路或物理重新配置硬件。同一台通用机器可以早上做工资核算,下午做弹道计算——因为“怎样做”只是另一组可以替换的比特。
想象一个厨房,菜谱和食材都放在同一个储柜里。厨师(处理器)不断地去储柜(内存)读取下一步菜谱(指令),并取用或更新食材(数据)。
想做别的菜?你不需要改造厨房。只需换一本菜谱——仍然使用相同的台面、烤箱和工具。
约翰·冯·诺依曼并没有“发明计算机”,也不是独自创造了存储程序思想。他做得极为出色的一点是把一个有前景的概念整理成清晰的表述,提出一种易于被其他工程师和实验室复现的设计。
冯·诺依曼深度参与了战时与战后计算项目,担任顾问并帮助理清早期设计的逻辑结构。他擅长以简单有序的方式解释复杂的技术选择,这很关键,因为早期电子计算发展迅速,多个团队同时在解决类似问题。
更重要的是,他撰写并传播了关于如何把程序指令存放在与数据相同的内存中的有影响力描述。那种清晰的表述让其他人更容易讨论、教学和复制这一方法。
名字往往不是贴给第一个提出想法的人,而是贴给那个把描述变成参照点的人。冯·诺依曼的文稿被广泛阅读、复制和引用——因此后来的读者自然地把“存储程序”组织与他联系起来。
这种简化也让历史更易传播:说“冯·诺依曼架构”比列出每个贡献者和报告要方便得多。但这种简称也会模糊真实的过程。
早期电子计算是一个跨机构、由数学家、工程师和程序员共同参与的协作过程。存储程序概念通过讨论、草稿、原型和各团队的修订而成熟。冯·诺依曼持久的作用是帮助凝练并传播这一思想——加速了它的采用,而不是独自创造它。
EDVAC(Electronic Discrete Variable Automatic Computer)是战后早期项目之一,旨在超越“单次用途”的机器。与硬件工作同样重要的是把设计思想写成清晰、可分享的文档。那时的计算机建造仍然接近实验工程——知识分散在实验室笔记、会议和少数专家的脑中。一份报告可以把这些零散见解变成其他团队可以讨论、批评和再利用的东西。
《EDVAC 报告初稿》(通常简称“EDVAC 报告”)以概念性的语言阐明了存储程序思想:计算机应当将程序指令保存在与数据相同类型的内部内存中。那种内存不仅是运行时保存数字的地方——它同时保存告诉机器下一步做什么的步骤。
这种表述让计算机更像一台可以通过改变内存内容而“重新分配任务”的通用机器。你不需要为从一种工作切换到另一种工作重新接线系统;你只需加载不同的指令序列。
除了概念本身外,报告帮助标准化了人们讨论计算机的方式:内存、控制、算术与输入/输出作为协同工作的不同功能部分。拥有共享的词汇和广泛阅读的描述,不仅解释了 EDVAC,也给更广泛的领域提供了一个共同的心智模型,以便构建、比较和改进存储程序计算机。
问“是谁发明了存储程序计算机?”并期待一个单一名字是很诱人的。但科学与工程很少以那种方式发生。想法往往并行发展,通过讨论被细化,只有在被展示为可工作的硬件时才具有说服力。
冯·诺依曼与存储程序概念紧密相关,但早期工作涉及许多人和团队:
存储程序计算机不是单一灵感。它结合了(1)指令可以像数据一样存在于内存中的概念飞跃,(2)构建可靠内存与控制单元的工程工作,以及(3)使该设计可用的编程实践。不同的人对不同的部分做出了贡献。
另一个原因是:提出一个想法不等于建造一台能日常工作的机器。早期的报告与讨论让概念更清晰;早期原型与生产系统证明了它的可行性。谨慎的历史要尊重这两类贡献,而不是强行给出单一“首创者”的结论。
当人们说“冯·诺依曼架构”时,通常指的是一种简单、广为教授的存储程序计算机组织模型。它不是一个品牌或单台历史机器——而是一个方便的标签,表示在许多计算机中以某种形式出现的基础方案。
在概念层面,这个模型看起来像:
关键在于 CPU 并没有为“程序”与“数字”各自保留一个独立的物理区域。它从内存中取出所需的一切。
CPU 通过重复一个常被描述为获取–译码–执行的循环来运行程序:
这种描述是简化的,但捕捉了核心:程序是一连串存储在内存中的指令,CPU 按序执行它们。
把指令与数据放在同一内存,使计算机在实践上成为通用:
因此“冯·诺依曼架构”最好被理解为对存储程序模型(包含 CPU、共享保存指令与数据的内存以及 I/O)的简称——这个概念与冯·诺依曼清晰的解释强相关,但早期存储程序的发展牵涉多方贡献者。
人们常把“冯·诺依曼”和“哈佛”当作对立的哲学。其实它们只是两种实际的安排方式,让计算机能获取所需的程序指令与数据。
在冯·诺依曼风格设计中,指令与数据存放在同一内存中,并通常通过同一主通路到达 CPU。
这在概念上很简单:程序就是内存里的字节,紧邻它要处理的数字、文本与图像。这也让通用计算变得直接——软件可以用与数据相同的机制被加载、修改和保存。
代价是:当指令与数据共享“道路”时,它们可能争用带宽。(有时被称为“瓶颈”,但关键就是共享。)
哈佛风格将指令存储与数据存储分离,通常也有独立的取指与数据通路。
这种分离有助于在读取或写入数据的同时取出下一条指令——在小而可预测的系统中很有用。一个简单例子是许多微控制器,程序代码放在 flash 中,而变量在 RAM 中。
现代 CPU 对软件而言常表现为“冯·诺依曼”(单一地址空间、单一程序模型),但内部借鉴哈佛式思想。例如常见的指令缓存(I-cache)与数据缓存(D-cache)分离。对你的程序来说仍像一个内存,但硬件可以更高效地并行取指与取数据。
要记住:没有普适的赢家。冯·诺依曼强调简单性与灵活性;哈佛强调分离与吞吐量。许多机器在二者之间权衡,以平衡可编程性、成本、功耗和速度。
存储程序计算机不仅能运行计算——它能把一组指令载入内存、执行,然后再载入另一组。这个转变使软件可重用、可共享:一个程序可以写一次、保存、复制、改进并分发,而无需接触硬件。
当程序存在于内存中,同一台物理计算机只需替换所读取的指令就能执行许多不同的工作。这就是“通用”的真正含义:一台机器,多种程序。计算机不再由单一工作流程定义;它变成一个平台。
一个相关的现代例子是你的笔记本可以运行邮件、游戏和电子表格。在底层,思想相同:硬件保持不变,不同的存储程序在切换应用时被加载并执行。
一旦把指令当作内存中的数据对待,构建帮助你写软件的分层工具就变得可行:
这些工具依赖于这样一个假设:程序可以像其他信息一样被存储、移动与处理。这就是为什么软件成为一个生态系统,而不是与特定接线设置绑定的一次性产物。
一个有用的视角:存储程序促成了编译器与操作系统,而这些又促成了现代开发工具——今天我们看到又一层抽象,使你能用自然语言描述应用并让工具生成可运行代码。例如 Koder.ai 是一种 vibe-coding 平台,你可以通过聊天界面构建网页、后端或移动应用,依赖大型语言模型和基于 agent 的工作流,加速从意图(“它应该做什么?”)到可执行指令(可导出、部署并通过快照回滚的源代码)的路径。
结果仍然是同样的良性循环:存储程序使更好的工具成为可能,更好的工具又使更复杂的程序成为可能——把计算机变成灵活的通用机器。
存储程序思想虽然让计算机更灵活,但也暴露了工程上仍需面对的实际限制:所谓的“冯·诺依曼瓶颈”。用日常比喻,就是连接 CPU(工人)与内存(仓库)之间的道路发生了拥堵。
在典型的存储程序设计中,程序指令和数据都存在内存。CPU 先取指令,再取所需数据,然后把结果写回——常常通过相同的连接。如果这条连接不能足够快地移动信息,CPU 就会等待,即使它本身可以更快地计算。
两个相关因素决定了瓶颈的严重性:
CPU 可能每秒能执行数十亿次操作,但如果内存不能持续提供指令与数据流,性能就受限于获取字节的最慢环节。
这是工程中广泛讨论的问题,现代计算机采用多种技术来减轻影响:
这些方法不能消除基础“道路”,但能让道路不那么拥堵——使 CPU 有更多时间在工作而不是等待。
存储程序概念不是博物馆里的展品——它就是日常计算保持灵活的方式。你的设备不需要被“重接线”就能做新事;它们只需把不同的指令载入内存并运行。
在手机上,点开一个应用图标会让操作系统把该应用的代码(指令)从存储载入内存,然后 CPU 执行它。在笔记本上,打开浏览器、编辑文档或运行游戏时也发生同样的事。在服务器上则更明显:机器可能运行着成千上万不断变化的工作负载——网页请求、数据库查询、后台任务——而无需更改硬件。
即便我们认为“像硬件一样”的功能,很多也由软件定义。网络路由、视频解码路径、照片增强和电源管理策略常通过固件与系统软件更新——新的指令,旧的设备。
像 Python 和 JavaScript 这样的语言通常通过解释器或虚拟机运行。你的源码并非由 CPU 直接执行,而是被翻译成一种结构化形式(字节码或内部指令),存放在内存中并逐步执行。Java 的 JVM、.NET、WebAssembly 运行时与浏览器的 JavaScript 引擎都依赖这一点:指令成为机器可以载入、移动与执行的数据结构。
因为指令“只是”内存中的信息,攻击者常尝试把恶意代码通过数据走私进去——经典的代码注入。防御措施如内存保护、代码签名和禁止执行的内存区域用来阻止不受信任的数据被当作可运行指令处理。
所有这些都回到了存储程序的中心承诺:通过软件实现灵活性——在相同的硬件上实现新行为。
在查看一台计算机或阅读规格时,这些问题可帮助你识别基本模型:
如果你想看更多类似的面向大众的文章,可浏览 /blog。
注: 如果你尝试用现代方式把“指令”变为可运行系统——无论是直接写代码还是使用像 Koder.ai 这样的聊天驱动构建平台——建议记录你的学习过程。Koder.ai 也有为发布内容和推荐提供积分的计划,这可以成为资助更多实验与教程的实用方式。
一个存储程序计算机将程序指令保存在与指令所操作的数据相同的内部存储中。要更换任务,你把不同的一组指令载入内存,而不是重新布线或物理重构机器。
在存储程序出现以前,许多机器实际上是用插板、跳线和开关设置来“编程”的。改变操作顺序可能需要数小时或数天的布线与重新测试,而且一个错误的连接可能引入难以发现的问题。
在这里,“内存”指的是计算机的快速工作存储(类似现代 RAM),CPU 在运行时可以频繁读取和写入。它不同于长期存储(如磁盘/SSD),后者用于在断电时保存程序和文件。
EDVAC 报告清晰地描述了指令与数据共享内部内存的组织方式,并提供了一套便于讨论的术语(内存、控制、算术、输入/输出)。这种清晰表达帮助别的团队更快地讨论、比较并构建类似系统。
冯·诺依曼之所以常被提及,主要是因为他的描述被广泛传播且易于引用,并非他是唯一的贡献者。存储程序思路是在更广泛的社区(工程师、数学家和早期程序员)中同时发展并相互促成的。
“冯·诺依曼架构”通常指的是一种模型:
这是描述存储程序组织的教学性标签,而不是对某台历史机器或某一位发明者的专属归属。
在冯·诺依曼风格中,指令与数据共享同一内存(通常通过相同的主通路到达 CPU)。在哈佛风格中,指令存储与数据存储是分开的(通常有独立通路)。
许多现代系统在软件视角上看似冯·诺依曼,但在硬件内部采用哈佛式的分离(例如独立的指令/数据缓存)。
“冯·诺依曼瓶颈”是指当 CPU 与内存共享一个受限通路来传输指令与数据时可能出现的性能限制。常见的缓解方法包括 缓存、预取 与 并行性(例如多核),这些手段能减少等待但不能完全消除底层限制。
因为程序就是可以载入内存的信息,你可以通过改变软件而不是更换芯片来更新行为。这就是同一部手机或笔记本能运行多个应用、固件/系统更新能在不改硬件的情况下添加功能的原因。
由于指令在内存中以数据形式存在,攻击者有时会试图把不受信任的数据当作可执行代码注入(例如代码注入攻击)。现代防护包括内存保护(禁止可执行内存区域)、代码签名以及其他将“可读数据”与“可执行代码”分离的机制。