Compiler và Interpreter: trình biên dịch khác trình thông dịch ở đâu?

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Máy tính chỉ hiểu mã máy, còn bạn viết bằng ngôn ngữ giống tiếng Anh. Cần một "người phiên dịch" ở giữa, và có hai kiểu làm việc khác nhau: biên dịch cả cuốn một lần, hoặc dịch và nói từng câu một. Đó là compiler và interpreter.

Compiler: dịch toàn bộ trước khi chạy

Compiler (trình biên dịch) đọc toàn bộ mã nguồn và tạo ra một file thực thi bằng mã máy. Sau đó bạn chạy file đó mà không cần mã nguồn hay trình biên dịch nữa. Ví dụ điển hình: C, C++, Go, Rust.

gcc chuong_trinh.c -o chuong_trinh
./chuong_trinh

Giống như dịch nguyên cuốn sách sang tiếng khác rồi phát hành. Ưu điểm và nhược điểm:

  • Chạy nhanh vì đã là mã máy được tối ưu.
  • Phát hiện nhiều lỗi sớm (cú pháp, kiểu dữ liệu) trước khi chạy.
  • Phụ thuộc nền tảng: file biên dịch cho Windows không chạy trực tiếp trên Linux.
  • Vòng lặp sửa-chạy chậm hơn vì phải biên dịch lại sau mỗi thay đổi.

Interpreter: dịch và chạy từng dòng

Interpreter (trình thông dịch) đọc mã nguồn và thực thi từng phần ngay, không tạo file thực thi riêng. Python và Ruby theo cách này (phần nhiều); JavaScript trong trình duyệt cũng được thông dịch/biên dịch tức thời.

python chuong_trinh.py

Giống như phiên dịch viên dịch trực tiếp từng câu khi hai bên đang trò chuyện.

  • Thử nghiệm nhanh: gõ và chạy ngay, có cả chế độ tương tác (REPL).
  • Dễ chạy trên nhiều nền tảng miễn là có trình thông dịch.
  • Chậm hơn chương trình đã biên dịch trong nhiều trường hợp.
  • Lỗi có thể chỉ lộ ra khi chạy đến đoạn đó.

Thực tế phức tạp hơn một chút

Ranh giới giữa hai kiểu không còn tuyệt đối:

  1. Bytecode: Java biên dịch ra bytecode, rồi máy ảo JVM chạy bytecode đó. Python cũng biên dịch nội bộ sang bytecode trước khi thực thi. C# cũng dùng mô hình tương tự.
  2. JIT (Just-In-Time): máy ảo biên dịch các đoạn code hay chạy thành mã máy ngay lúc chạy để tăng tốc. Các engine JavaScript hiện đại làm vậy.
  3. Transpiler: dịch từ ngôn ngữ này sang ngôn ngữ khác ở cùng mức, ví dụ TypeScript sang JavaScript.

Điều quan trọng cần nhớ: "biên dịch hay thông dịch" là đặc điểm của cách triển khai hơn là của bản thân ngôn ngữ. Cùng một ngôn ngữ có thể có cả trình biên dịch lẫn trình thông dịch.

Bảng so sánh

Tiêu chíCompilerInterpreter
Cách làmDịch toàn bộ trướcDịch và chạy dần
Kết quảFile thực thiChạy trực tiếp
Tốc độ chạyThường nhanh hơnThường chậm hơn
Phát hiện lỗiNhiều lỗi trước khi chạyPhần nhiều khi chạy
Ví dụC, C++, Go, RustPython, Ruby, PHP

Điều này ảnh hưởng gì đến bạn?

  • Khi gặp lỗi lúc biên dịch (compile error), chương trình chưa hề chạy; hãy sửa theo thông báo của compiler.
  • Lỗi lúc chạy (runtime error) xuất hiện khi chương trình đang thực thi, ví dụ chia cho 0 hay mở file không tồn tại.
  • Khi phân phối ứng dụng, chương trình biên dịch tiện vì người dùng không cần cài thêm gì; chương trình thông dịch thì cần môi trường chạy.

Quan sát bytecode trong Python

Bạn có thể tận mắt thấy "bước biên dịch ngầm" của Python bằng module dis:

import dis

def cong(a, b):
    return a + b

dis.dis(cong)

Kết quả liệt kê các lệnh bytecode đơn giản như nạp hai biến, cộng chúng, trả về kết quả (tên lệnh cụ thể khác nhau giữa các phiên bản Python). Máy ảo Python sau đó thực thi từng lệnh này. Đây là minh họa rõ nhất rằng ranh giới "thông dịch hay biên dịch" không tuyệt đối.

Bạn cũng có thể thử so sánh hai kiểu làm việc trên cùng một bài toán:

  1. Viết chương trình đếm từ 1 đến 100 triệu và cộng dồn bằng C, biên dịch với gcc -O2.
  2. Viết đúng chương trình đó bằng Python.
  3. Đo thời gian chạy của cả hai bằng lệnh time (Linux, macOS) hoặc công cụ tương đương.

Thông thường bản C nhanh hơn nhiều lần, vì mã máy được tối ưu và không có chi phí thông dịch từng lệnh. Nhưng đổi lại, bản Python ngắn hơn, dễ viết hơn và dễ thay đổi. Chọn công cụ là chọn sự đánh đổi phù hợp với bài toán.

Kết luận

Compiler dịch cả cuốn rồi mới phát hành, interpreter dịch tới đâu chạy tới đó, còn thực tế nhiều ngôn ngữ kết hợp cả hai bằng bytecode và JIT. Hiểu điều này giúp bạn đọc thông báo lỗi đúng ngữ cảnh và chọn công cụ hợp lý. Hãy thử biên dịch một chương trình C và chạy một script Python để tự cảm nhận sự khác biệt.

Bạn có thể tiếp tục hành trình với những khóa học lập trình trên codebem.com, học theo tốc độ của riêng mình.

author_photo
Nguyễn Đình Cường

0 comment