+3

Python Guru Series 🐍🐍🐍 - Part 2: Các trình thông dịch trong Python

Xin chào mọi người,
Hôm nay, trong bài viết thứ hai của loạt bài Python Guru Series, mình muốn chia sẻ cho các bạn về một chủ đề thú vị: Các trình biên dịch và thông dịch trong Python.
Mình tin rằng đây là một khái niệm quan trọng mà mọi lập trình viên, không chỉ những Python Developer không nên bỏ qua.
Ok, mình cùng bắt đầu thôi.

Tổng quan về Trình Biên Dịch và Trình Thông Dịch

Trong lĩnh vực khoa học máy tính, các khái niệm về trình biên dịch và trình thông dịch là những khái niệm rất quan trọng. Bất kỳ ngôn ngữ lập trình nào cũng cần một trình biên dịch hoặc trình thông dịch để dịch mã nguồn của bạn thành mã máy thứ máy tính có thể hiểu và thực thi.

Minh họa về trình biên dịch và thông dịch

Trình biên dịch (compiler) là một chương trình dịch toàn bộ mã nguồn của bạn thành mã máy. Sau đó, máy tính sẽ thực thi chương trình dựa trên các mã máy đã được biên dịch này.

Ngược lại, trình thông dịch (interpreter) là một chương trình thực thi trực tiếp mã nguồn mà không cần biên dịch trước. Trình thông dịch sẽ tiến hành dịch từng dòng mã nguồn thành mã máy để máy tính thực thi trực tiếp.

Hãy tưởng tượng trình biên dịch như một người phiên dịch (translator) chuẩn bị tài liệu trước, dịch toàn bộ tài liệu trước khi gặp đối tác. Thông dịch giống như một người phiên dịch (interpreter) dịch từng ý, từng câu của đối tác khi họ truyền đạt.

Nhìn chung, các trình thông dịch không được đánh giá cao về tốc độ so với các trình biên dịch. Vì trình biên dịch dịch mã nguồn trước, nó cũng có thể phát hiện lỗi hiệu quả hơn so với trình thông dịch. Nó cũng cung cấp sự tối ưu hóa cao của mã máy. Tuy nhiên, các trình thông dịch lại cung cấp sự linh hoạt cao. Chúng cho phép việc thông dịch và thực thi ngay lập tức từng dòng mã nguồn. Điều này giúp dễ dàng sửa lỗi và gỡ lỗi vì mã nguồn có thể được tạm dừng và sửa đổi ngay lập tức. Khác với khi sử dụng trình biên dịch, nơi mã nguồn phải được biên dịch lại toàn bộ nếu xảy ra lỗi.

Tùy thuộc vào mục tiêu thiết kế, các ngôn ngữ lập trình khác nhau sẽ chọn chiến lược sử dụng trình biên dịch và trình thông dịch sao cho hợp lý. Một số ngôn ngữ biên dịch nổi tiếng như C và C++ sử dụng các trình biên dịch như GCC và G++. Java là một trường hợp đặc biệt. Nó vừa được biên dịch và thông dịch. Ban đầu, Java được biên dịch thành bytecode, sau đó được thông dịch thành mã máy bởi JVM (Máy ảo Java). JavaScript, đại diện của các ngôn ngữ kịch bản, là một ngôn ngữ thông dịch.

Python là ngôn ngữ Biên Dịch hay Thông Dịch?

Python được coi là một ngôn ngữ thông dịch. Python sử dụng một trình thông dịch để dịch mã Python thành các lệnh mà máy tính có thể thực thi.

Khi chúng ta nói về trình thông dịch Python, chúng ta thường sử dụng các trình thông dịch với đường dẫn /usr/bin/python trong môi trường hệ thống hoặc sử dụng môi trường ảo (virtual enviroment) để thực thi các tệp .py với câu lệnh magic sau: /usr/bin/python your_program.py. Tuy nhiên, thông dịch chỉ là một nhiệm vụ. Trước khi máy tính thực thi các câu lệnh, trình thông dịch Python thực hiện các nhiệm vụ sau:

  • Phân tích từ vựng (Lexing): Bộ phân tích từ vựng (Lexer) sẽ tiến hành biến mã nguồn thành một chuỗi các token. Một token là sự đại diện của các kí tự syntax trong code ở mức đơn giản.
  • Phân tích cú pháp (Parsing): Trong trình phân tích cú pháp, các token từ vựng được kiểm tra về cú pháp và ngữ pháp. Kết quả đầu ra của trình phân tích cú pháp là một cây cú pháp trừu tượng (AST), mô tả mã nguồn của bạn như một cấu trúc cây.
  • Biên dịch (Compiling): Dựa trên cây AST, trình biên dịch tạo ra các mã Python bytecode. Bạn có thể đã thấy tệp mã nguồn .py chuyển thành tệp pythonfile.cpython.pyc trong thư mục pycache sau khi chạy một chương trình Python. Các Python bytecode chứa các lệnh, chỉ thị cho máy tính xử lý.
  • Thông dịch (Interpreting): Trình thông dịch xử lý từng bytecode và thực hiện các thao tác được chỉ định.

Bạn thấy đấy, có nhiều bước khi một trình thông dịch dịch mã Python để máy tính thực thi. Có nhiều trình thông dịch khác nhau ngoài kia, hãy cùng xem qua một số trong số chúng.

Các trình thông dịch trong Python

CPython

Mặc định, Python sử dụng CPython làm trình thông dịch. Nó biên dịch mã Python thành mã byte trung gian, sau đó được thông dịch bởi Python interpreter. CPython cung cấp mức độ tương thích cao nhất với các gói Python và các mô-đun mở rộng C. CPython là interpreter gốc của Python và tương thích với tất cả các thư viện và gói tiêu chuẩn của Python. Bất kỳ mã Python nào được viết đều có thể chạy trên CPython mà không cần sửa đổi.

PyPy

PyPy là một trình biên dịch được viết bằng RPython (Restricted Python), một tập hợp con của Python được thiết kế để dễ dàng biên dịch thành mã máy hiệu suất cao. PyPy sử dụng một máy ảo để thực thi mã, tương tự như CPython. Tuy nhiên, nhờ trình biên dịch Just-In-Time (JIT), tương tự như ý tưởng của Java, máy ảo của PyPy có thể biên dịch và tối ưu hóa mã trong khi nó chạy, tăng đáng kể tốc độ thực thi. Theo một bài kiểm tra trên trang web chính thức của PyPy, PyPy hiện chạy các bài kiểm tra nhanh hơn CPython hơn 4,5 lần. Tuy nhiên, PyPy hiện chỉ hỗ trợ một số phiên bản Python 3.10, 3.9 và 2.7.

Jython

Jython là một hiện thực của Python biên dịch mã Python thành bytecode Java, sau đó được thực thi bởi JVM. Ngoài ra, nó có thể nhập và sử dụng bất kỳ lớp Java nào như một mô-đun Python. Nếu bạn cần giao tiếp với một cơ sở mã Java hiện có hoặc có lý do khác để viết mã Python cho JVM, Jython là lựa chọn tốt nhất. Jython hiện chỉ hỗ trợ tới Python 2.7.

IronPython

IronPython là một trình thông dịch Python được hiện thực bằng C# và chạy trên nền tảng .NET Framework. Nó cho phép tích hợp với các thư viện .NET và thực thi mã Python trên nền tảng .NET. IronPython hiện chỉ hỗ trợ tới Python 2.7 và Python 3.4.

MicroPython

MicroPython là một trình thông dịch Python được thiết kế để chạy trên các vi điều khiển và các thiết bị nhỏ. Nó được tối ưu hóa cho tài nguyên hạn chế và thường được sử dụng trong các ứng dụng IoT.

Thực nghiệm

Trong phần này để chứng minh rằng việc lựa chọn compiler/intepreter có thể cải thiện đáng kể hiệu năng cho chương trình của bạn. Mình sẽ tiến hành benchmark tốc độ thực thi của 2 trình thông dịch Cpython và Pypy trên 2 chương trình sum.py ( tính tổng tới một số đủ lớn) và fibonnaci.py (tìm số fibonnaci thứ n). Đây là hai chương trình khá quen thuộc đều thiên về tính các tính vụ tính toán sử dụng nhiều CPU (CPU-bound tasks).

Benchmark được thực hiện trên máy PC chạy hệ điều hành Ubuntu 22.04 với bộ vi xử lý Intel® Core™ i3-10100 CPU @ 3.60GHz , 4 cores, 8 threads, , 32 GB RAM. Với 2 chương trình này, mình sẽ thực hiện excecute 3 lần và tính thời gian thực thi trung bình.
Hai trình thông dịch được sử dụng cho benchmark Cpython và Pypy.

Cpython là trình thông dịch default của Python, nó đã được cài sẵn khi bạn cài đặt Python. Còn với Pypy thì bạn có thể download từ trang chủ của Pypy hoặc sử dụng pyenv để cài đặt. Chi tiết mình sẽ có một bài viết về cách quản lý các phiên bản khác nhau của Python trong dự án thực tế sau.

Chương trình đầu tiên là chương trình tính tổng

Ở đây mình thực hiện tính tổng các số từ 0 tới 1 tỷ.

Chương trình sum.py với n = 1000000000

Cpython

#python3 sum.py
Sum = 499999999500000000
Sum = 499999999500000000
Sum = 499999999500000000
Average time: 35.575 seconds

Pypy

#/usr/bin/pypy3.10 sum.py 
Sum = 499999999500000000
Sum = 499999999500000000
Sum = 499999999500000000
Average time: 0.816 seconds

Chương trình thứ hai là chương trình tìm số fibonnaci thứ n.

Ở đây mình sử dụng đệ quy với n = 40. Đòi mức độ tính toán, đệ quy tương đối lớn. Chương trình fibonnaci thứ n, với n = 40

Cpython

#python3 fibonnaci.py 
Average time: 22.862 seconds

Pypy

#/usr/bin/pypy3.10 fibonnaci.py 
Average time: 2.034 seconds

Nhận xét

Thông qua kết quả tính toán toán của hai ví dụ trên giúp ta nhận thấy rằng. Đối với các chương trình có task vụ thiên về tính toán sử dụng CPU. Áp dụng Pypy cho chúng ta kết quả vượt trội hơn nhiều lần so với sử dụng Cpython. Cả Cpython và Pypy đều có nhiều điểm tương đồng, khi đều sở hữu Global Interpreter Lock (GIL) cái làm cho Python trở thành ngôn ngữ single-thread base và khả năng tương thích với nhiều thư viện C libaries. Tuy nhiên, Pypy tập trung cải thiện hiệu năng ở runtime khi sử dụng Just-In-Time-Compiler để gia tăng tốc độ xử lý các mã code.

Đến đây, bạn có thể có nhiều câu hỏi về tại sao không chọn PyPy thay vì CPython. Với nhiều trình thông dịch như vậy, bạn nên chọn interpreter nào? Sự thật là, nó phụ thuộc vào vấn đề bạn cần giải quyết. CPython là trình thông dịch mặc định của Python. Nó được tạo ra cùng với sự phát triển của Python. Chúng ta vẫn sử dụng nó để phát triển các ứng dụng hàng ngày. CPython được coi là trình thông dịch chính thức của Python, với một cộng đồng lớn và hỗ trợ cho tất cả các phiên bản Python.

Đối với các vấn đề tính toán hiệu suất cao, PyPy có thể là lựa chọn đúng. PyPy có thể giúp bạn tận dụng các khả năng tối ưu hóa của trình biên dịch. PyPy phù hợp với các ứng dụng đòi hỏi hiệu suất tính toán cao, như các ứng dụng khoa học, tài chính và xử lý dữ liệu lớn. Tuy nhiên, PyPy cũng chỉ hỗ trợ một số phiên bản cụ thể của Python và có một cộng đồng nhỏ hơn nhiều so với CPython.

Tương tự, Jython, IronPython và MicroPython phục vụ các mục đích cụ thể cho các vấn đề hẹp và chỉ hỗ trợ một số phiên bản Python nhất định.

Tổng kết

Trong bài viết hôm nay, mình đã chia sẻ một số kiến thức về các trình biên dịch và các trình thông dịch phổ biến của Python. Đây là những khái niệm tương đối quan trọng bởi các trình biên dịch/trình thông dịch đóng vai trò xương sống trong việc thực thi một ngôn ngữ. Chúng cũng góp phần ảnh hưởng đáng kể đến hiệu suất ứng dụng của bạn.

Python là một ngôn ngữ thông dịch, điều này gắn liền với lịch sử và đặc tính của nó. Python đã và đang trở nên ngày càng mạnh mẽ theo thời gian. Thực tế, Python là một ngôn ngữ linh hoạt, đa năng và đang được áp dụng hàng ngày trong nhiều lĩnh vực.

Thế là kết thúc phần hai của trong Python Guru Series. Hi vọng các bạn đã nhận được các góc nhìn thú vị

Cảm ơn các bạn đã dành thời gian.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí