Dữ liệu & CPU/Mô hình von Neumann — điều gì xảy ra khi bạn chạy ./program
9/23
Bài 9 / 23~15 phútMáy chạy thế nàoMiễn phí lượt xem

Mô hình von Neumann — điều gì xảy ra khi bạn chạy ./program

CPU, bộ nhớ, bus và I/O ghép thành máy tính thế nào. Khái niệm stored-program, nút thắt von Neumann, và bức tranh tổng thể trước khi đào sâu từng phần.

TL;DR: Mô hình von Neumann mô tả máy tính gồm 4 thành phần cốt lõi — CPU, bộ nhớ chính, bus và I/O — kết nối qua một bus dùng chung. Điểm then chốt: chương trình (lệnh) và dữ liệu cùng nằm trong một bộ nhớ, cùng dạng bit — gọi là stored-program concept. Chính thiết kế này cho phép máy tính đa năng tự thay đổi hành vi bằng cách nạp chương trình khác. Nhưng bus dùng chung cũng tạo ra "nút thắt von Neumann" — lý do CPU hiện đại cần cache.

Bạn gõ ./program trong terminal rồi nhấn Enter. Chưa đến một giây sau, kết quả hiện ra màn hình. Trong khoảng thời gian đó, hàng triệu lệnh máy đã chạy, hàng triệu byte dữ liệu đã di chuyển, và CPU đã thực hiện chu kỳ fetch-decode-execute hàng triệu lần.

Nhưng tất cả bắt đầu từ một câu hỏi đơn giản hơn: làm thế nào một cỗ máy điện tử "biết" phải làm gì? Và vì sao cùng một CPU có thể chạy được trình duyệt, trình biên dịch, game lẫn máy chủ web?

Bài này giải thích bức tranh tổng thể — mô hình von Neumann, stored-program concept, và nút thắt kiến trúc mà mọi CPU hiện đại vẫn đang vật lộn. Đây là nền móng trước khi bài tiếp theo đào sâu vào từng chu kỳ fetch-decode-execute.

1. Analogy — căn bếp nhà hàng

Hình dung một nhà bếp chuyên nghiệp:

  • Công thức nấu ăn được in trên giấy, xếp trong kệ hồ sơ.
  • Nguyên liệu (thịt, rau, gia vị) cũng để trong kho, ngay cạnh kệ hồ sơ.
  • Đầu bếp (control unit + ALU) lấy từng bước từ công thức, lấy nguyên liệu từ kho, thực hiện xong bước đó rồi lấy bước tiếp.
  • Băng chuyền (bus) mang nguyên liệu và công thức từ kho ra bàn đầu bếp.
  • Cửa ra vào (I/O) nhận nguyên liệu từ bên ngoài và giao món ăn ra.

Điểm mấu chốt: công thức và nguyên liệu cùng nằm trong một kho, cùng dạng "thứ cần lấy". Đầu bếp không cần biết thứ mình lấy là lệnh hay dữ liệu — đó là việc của bối cảnh thực thi. Đây chính là stored-program concept.

Nhà bếpMáy tính (von Neumann)
Đầu bếpCPU (control unit + ALU)
Công thức nấuLệnh máy (machine instructions)
Nguyên liệuDữ liệu (data)
Kho chứa công thức + nguyên liệuBộ nhớ chính (RAM)
Băng chuyền giữa kho và đầu bếpBus (địa chỉ, dữ liệu, điều khiển)
Cửa nhận nguyên liệu / giao mónI/O (bàn phím, màn hình, đĩa)
💡 Cách nhớ

Stored-program: chương trình cũng là dữ liệu — cùng kho, cùng dạng bit. Đây là lý do máy tính đa năng; thay đổi chương trình là thay đổi hành vi, không phải thay đổi phần cứng.

2. Bốn thành phần cốt lõi

2.1 CPU — đầu não xử lý

CPU (Central Processing Unit) gồm hai phần chính:

  • Control Unit (CU): đọc lệnh từ bộ nhớ, giải mã lệnh đó có nghĩa là gì, ra lệnh cho các thành phần khác thực thi. CU không tự tính toán — nó điều phối.
  • ALU (Arithmetic Logic Unit): thực hiện phép tính số học (cộng, trừ, nhân, chia) và phép logic (AND, OR, NOT, so sánh). Mọi phép tính trong chương trình của bạn đều qua ALU.

CPU còn có một tập register — vùng nhớ cực nhỏ, cực nhanh, nằm ngay trong chip. Register lưu dữ liệu đang tính, địa chỉ lệnh tiếp theo (Program Counter), kết quả trung gian. Bài 03 sẽ đào sâu hơn về register.

2.2 Bộ nhớ chính — nơi cất chương trình và dữ liệu

RAM (Random Access Memory) là bộ nhớ chính trong mô hình von Neumann. RAM lưu cả hai:

  • Lệnh máy — tức chương trình đã được nạp vào.
  • Dữ liệu — biến, mảng, cấu trúc mà chương trình đang xử lý.

Cả hai loại đều là bit, cùng địa chỉ, cùng tổ chức. CPU phân biệt "đây là lệnh hay dữ liệu" qua ngữ cảnh thực thi (đang ở pha fetch lệnh hay đang truy cập dữ liệu), không phải qua cấu trúc vật lý.

RAM là bộ nhớ volatile — mất điện là mất dữ liệu. Chương trình ./program nằm trên đĩa; khi bạn chạy nó, hệ điều hành sao chép lệnh máy từ đĩa vào RAM trước, CPU mới đọc được.

2.3 Bus — đường truyền dùng chung

Bus là tập hợp đường dây điện kết nối CPU, RAM và I/O. Có ba loại bus trong mô hình chuẩn:

  • Address bus: CPU gửi địa chỉ muốn đọc/ghi (một chiều: CPU → RAM/I/O).
  • Data bus: dữ liệu di chuyển hai chiều giữa CPU và RAM/I/O.
  • Control bus: tín hiệu điều khiển — đọc hay ghi, bộ nhớ hay I/O, v.v.

Mỗi lần CPU đọc một byte từ RAM: CU đặt địa chỉ lên address bus, gửi tín hiệu "đọc" lên control bus, RAM trả byte về qua data bus. Mỗi thao tác đọc/ghi đều đi qua bus này.

2.4 I/O — cửa ngõ với thế giới ngoài

I/O (Input/Output) là thiết bị và controller kết nối máy tính với thế giới bên ngoài: bàn phím, màn hình, đĩa cứng, card mạng. Trong mô hình von Neumann, I/O được kết nối qua bus và có địa chỉ riêng (memory-mapped I/O hoặc port-mapped I/O — chi tiết trong bài sau về I/O).

3. Stored-program concept — phát kiến then chốt

Trước von Neumann, máy tính sớm như ENIAC (1945) được "lập trình" bằng cách cắm lại dây điện vật lý — thay đổi cấu trúc mạch để thay đổi hành vi. Mỗi lần đổi bài toán là hàng giờ đến hàng ngày kéo cáp.

John von Neumann (cùng nhóm Moore) đề xuất trong báo cáo 1945: lưu chương trình vào bộ nhớ, cùng chỗ với dữ liệu. CPU đọc lệnh từ bộ nhớ giống như đọc dữ liệu. Để đổi hành vi máy, chỉ cần nạp chương trình khác vào RAM — không cắm lại dây.

Đây là lý do máy tính hiện đại đa năng: cùng một phần cứng chạy được Python, Java, C, hay bất kỳ chương trình nào — miễn là lệnh máy tương ứng được nạp đúng vào RAM.

flowchart LR
  subgraph CPU["CPU"]
    CU["Control Unit"]
    ALU["ALU"]
    REG["Registers"]
  end
  subgraph MEM["Bo nho chinh (RAM)"]
    INS["Lenh may\n(Instructions)"]
    DAT["Du lieu\n(Data)"]
  end
  IO["I/O\n(ban phim, man hinh, dia)"]

  CU -- "doc lenh / doc-ghi du lieu" --> MEM
  CU -- "dieu khien" --> ALU
  ALU -- "ket qua" --> REG
  REG -- "du lieu tinh toan" --> ALU
  CU -- "dia chi + dieu khien" --> IO
  MEM -- "data bus" --> CU
  IO -- "data bus" --> CU

3.1 So sánh với kiến trúc Harvard

Kiến trúc Harvard (dùng trong vi điều khiển nhúng như AVR, PIC) tách bộ nhớ lệnh và bộ nhớ dữ liệu thành hai vùng riêng biệt với hai bus riêng:

Tiêu chíVon NeumannHarvard
Bộ nhớ lệnh và dữ liệuChung mộtTách riêng
BusDùng chungHai bus độc lập
Băng thôngBị chia sẻCao hơn (hai bus song song)
Linh hoạtCao (chương trình tự sửa được)Thấp hơn
Ứng dụng điển hìnhCPU đa năng (x86, ARM)Vi điều khiển nhúng (AVR, PIC)

CPU hiện đại như x86 và ARM về mặt kiến trúc ngoài là von Neumann, nhưng bên trong dùng kiến trúc Harvard sửa đổi — cache lệnh (L1i) và cache dữ liệu (L1d) tách riêng để tăng băng thông. Đây là cầu nối giữa hai mô hình.

4. Vòng lặp cơ bản của CPU

Mọi thứ CPU làm đều xoay quanh một vòng lặp vô tận:

  1. Fetch: đọc lệnh tại địa chỉ Program Counter chỉ tới (từ RAM qua bus).
  2. Decode: giải mã lệnh — đây là lệnh cộng, lệnh nhảy, lệnh đọc bộ nhớ, hay loại nào?
  3. Execute: thực thi — ALU tính toán, hoặc CU điều phối đọc/ghi bộ nhớ, hoặc thay đổi Program Counter.
  4. Lặp lại từ bước 1.

Đây là fetch-decode-execute cycle — chủ đề trọng tâm của bài tiếp theo. Bài này chỉ giới thiệu vòng lặp như một teaser; bài 02 sẽ trace từng bước với lệnh cụ thể.

5. Đào sâu (tuỳ chọn) — nút thắt von Neumann

📚 Đào sâu (tuỳ chọn)

Nút thắt von Neumann (von Neumann bottleneck) là hệ quả trực tiếp của thiết kế bus dùng chung.

Vì lệnh và dữ liệu đều đi qua cùng một bus, CPU phải luân phiên: fetch lệnh → xong → đọc dữ liệu → xong → fetch lệnh tiếp... Bus chỉ có một làn, mọi thứ xếp hàng. Tốc độ CPU tăng nhanh hơn tốc độ bus và RAM rất nhiều — từ thập niên 1980, CPU đã nhanh hơn RAM hàng chục đến hàng trăm lần.

Hệ quả: dù ALU có thể tính hàng tỷ phép mỗi giây, nó thường phải ngồi chờ dữ liệu từ RAM. Đây là lý do sinh ra cache (L1, L2, L3) — bộ nhớ nhỏ, cực nhanh, nằm ngay trong chip, giảm số lần CPU phải ra bus hỏi RAM. Course 2 sẽ đào sâu về cache; bài này chỉ cần ghi nhớ: nút thắt von Neumann là nguyên nhân gốc rễ khiến "truy cập bộ nhớ chậm" là mối lo hiệu năng số một.

Kiến trúc Harvard sửa đổi trong CPU thật (cache lệnh L1i tách khỏi cache dữ liệu L1d) giảm nhẹ vấn đề này bằng cách cho CPU fetch lệnh và đọc dữ liệu đồng thời — nhưng bus ngoài ra RAM vẫn là bottleneck ở tầng cao hơn.

6. Áp dụng vào code của bạn

Vì sao "chương trình cũng là dữ liệu" quan trọng với lập trình viên?

Stored-program concept là nền móng của nhiều kỹ thuật quan trọng:

  • Compiler và interpreter: chương trình đọc chương trình khác (source code) như dữ liệu, rồi sinh ra hoặc thực thi chương trình mới.
  • JIT compilation: JVM đọc bytecode (dữ liệu), sinh lệnh máy (chương trình mới), nạp vào RAM và chạy.
  • Mã độc (malware): khai thác đúng tính chất này — ghi dữ liệu vào vùng nhớ mà CPU sẽ đọc như lệnh (buffer overflow, code injection).
  • Self-modifying code: chương trình ghi lên vùng nhớ chứa chính lệnh của nó (dùng trong optimizer, packer, obfuscator).

Vì sao truy cập bộ nhớ thường là nút thắt hiệu năng?

Khi bạn loop qua một mảng lớn hay đọc nhiều object rải rác trong heap, CPU thường không bị giới hạn bởi số phép tính — mà bị giới hạn bởi thời gian chờ RAM trả dữ liệu (cache miss). Tư duy hiệu năng đúng là:

  • Giảm số lần "ra ngoài" bus hỏi RAM (cache-friendly data layout, locality of reference).
  • Tính nhiều hơn, đọc ít hơn — prefetch dữ liệu, dùng SIMD, tránh pointer-chasing ngẫu nhiên.

Đây là lý do ArrayList thường nhanh hơn LinkedList trên thực tế dù độ phức tạp lý thuyết như nhau — ArrayList lưu liên tục trong RAM, cache-friendly; LinkedList nhảy loạn khắp heap, mỗi bước là một cache miss tiềm ẩn.

7. Liên hệ các bài khác

  • Bài 01 (module 01) — Bit, byte và hệ cơ số: lệnh máy và dữ liệu trong RAM đều là bit — khái niệm bài 01 trực tiếp nền tảng cho bài này.
  • Bài 02 (module này) — Fetch-decode-execute: đào sâu vào vòng lặp CPU đã giới thiệu ở mục 4. Đọc bài này trước để có bức tranh tổng thể.
  • Bài 03 (module này) — Register và ALU: chi tiết về thành phần CPU đề cập ở mục 2.1.
  • Course 2 — Cache và bộ nhớ: nút thắt von Neumann (mục 5) là lý do chính Course 2 tồn tại — cache giải quyết vấn đề gì và hoạt động ra sao.

8. Tóm tắt

  • Mô hình von Neumann gồm 4 thành phần: CPU (control unit + ALU + register), bộ nhớ chính (RAM), bus (address/data/control), và I/O.
  • Stored-program concept: lệnh và dữ liệu cùng nằm trong một bộ nhớ, cùng dạng bit. Đây là nền tảng của máy tính đa năng.
  • CPU đọc lệnh từ RAM qua bus, decode rồi execute — vòng lặp fetch-decode-execute chạy liên tục.
  • Kiến trúc Harvard tách bộ nhớ lệnh và dữ liệu; CPU hiện đại dùng Harvard sửa đổi (cache L1i/L1d tách) bên trong nhưng giao diện ngoài vẫn von Neumann.
  • Nút thắt von Neumann: bus dùng chung khiến tốc độ bị giới hạn bởi băng thông RAM — lý do cache ra đời.
  • "Chương trình cũng là dữ liệu" là nền tảng cho compiler, JIT, interpreter và cả mã độc.
  • Truy cập bộ nhớ, không phải phép tính, thường là nút thắt hiệu năng thực tế.

9. Tự kiểm tra

Tự kiểm tra
Q1
Stored-program concept nghĩa là gì? Tại sao đây là phát kiến quan trọng so với máy tính trước đó?
Stored-program có nghĩa là lệnh máy (chương trình) và dữ liệu cùng được lưu trong một bộ nhớ, cùng dạng bit, có thể đọc và ghi như nhau. Trước đó, máy như ENIAC phải cắm lại dây điện vật lý để thay đổi hành vi — rất chậm và hạn chế. Với stored-program, thay đổi chương trình chỉ cần nạp dữ liệu khác vào RAM, cho phép một phần cứng dùng chung chạy vô số chương trình khác nhau.
Q2
Bus trong mô hình von Neumann gồm những gì? Mỗi loại đảm nhiệm vai trò gì?
Bus gồm ba loại: address bus (CPU gửi địa chỉ muốn đọc/ghi, một chiều từ CPU ra), data bus (dữ liệu di chuyển hai chiều giữa CPU và RAM/I/O), và control bus (tín hiệu điều khiển — đọc hay ghi, bộ nhớ hay I/O). Mỗi lần CPU đọc một byte từ RAM phải dùng cả ba: đặt địa chỉ lên address bus, tín hiệu "đọc" lên control bus, nhận dữ liệu từ data bus.
Q3
Vì sao nút thắt von Neumann (von Neumann bottleneck) xuất hiện? Kiến trúc máy tính giải quyết nó bằng cách nào?
Nút thắt xuất hiện vì lệnh và dữ liệu dùng chung một bus — CPU phải luân phiên fetch lệnh và đọc dữ liệu, không thể làm đồng thời. CPU ngày càng nhanh hơn RAM rất nhiều, nên phần lớn thời gian CPU chờ bus và RAM. Giải pháp chính là cache (L1, L2, L3) — bộ nhớ nhỏ cực nhanh ngay trong chip, giảm số lần CPU phải ra bus hỏi RAM. CPU hiện đại còn tách cache lệnh (L1i) và cache dữ liệu (L1d) riêng — kiến trúc Harvard sửa đổi — để fetch lệnh và đọc dữ liệu có thể xảy ra đồng thời.
Q4
Sự khác biệt chính giữa kiến trúc von Neumann và kiến trúc Harvard là gì? Mỗi loại phù hợp cho ứng dụng nào?
Von Neumann dùng chung một bộ nhớ và một bus cho cả lệnh lẫn dữ liệu — linh hoạt, dễ lập trình, phù hợp CPU đa năng (x86, ARM). Harvard tách bộ nhớ và bus lệnh khỏi bộ nhớ và bus dữ liệu — băng thông cao hơn (hai đường song song), nhưng kém linh hoạt hơn, phù hợp vi điều khiển nhúng (AVR, PIC, DSP) nơi chương trình ít khi thay đổi và cần hiệu năng I/O cao. CPU hiện đại là Harvard sửa đổi bên trong (cache tách) nhưng giao diện ngoài vẫn von Neumann.
Q5
Tại sao ArrayList thường nhanh hơn LinkedList trong Java dù độ phức tạp lý thuyết tương đương? Liên hệ với mô hình von Neumann.
ArrayList lưu phần tử liên tục trong một vùng RAM — CPU đọc tuần tự, cache prefetch hoạt động tốt, ít cache miss. LinkedList mỗi node là một object riêng trên heap, địa chỉ rải rác — mỗi bước nhảy pointer là một lần CPU ra bus hỏi RAM (cache miss). Liên hệ với von Neumann: vì CPU và RAM dùng chung bus, mỗi cache miss phải chờ bus và RAM trả dữ liệu. Nút thắt von Neumann làm rõ: nút thắt thực tế là băng thông bộ nhớ, không phải số phép tính. Code tối ưu giảm số lần chạm bộ nhớ, không chỉ giảm số phép tính.
Q6
Vì sao JIT compiler và mã độc (malware) đều liên quan đến stored-program concept?
Cả hai khai thác cùng tính chất: lệnh và dữ liệu không khác nhau về bản chất — chỉ là bit trong RAM. JIT compiler đọc bytecode (dữ liệu), sinh ra lệnh máy mới (chương trình), ghi vào vùng nhớ thực thi, rồi CPU đọc vùng đó như lệnh — hoàn toàn hợp lệ. Mã độc dùng kỹ thuật tương tự nhưng phi pháp: ghi dữ liệu vào vùng nhớ mà CPU sẽ đọc như lệnh (buffer overflow, code injection). Stored-program là con dao hai lưỡi — cho phép máy tính linh hoạt nhưng cũng tạo ra lớp tấn công căn bản nhất.

Bài tiếp theo: Chu kỳ fetch-decode-execute

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên