Go là một dự án mã nguồn mở, chúng ta có thể dễ dàng có được mã nguồn của nó, nó có cấu trúc dự án rất phức tạp và cơ sở mã khổng lồ, Go ngày nay có gần 1,5 triệu dòng mã nguồn, chứa gần 1,4 triệu dòng mã Go, chúng ta có thể sử dụng các lệnh như sau để xem số dòng mã trong dự án:
Khi phát triển Go, toàn bộ cơ sở mã thay đổi theo thời gian, vì vậy kết quả thống kê ở trên khác nhau mỗi ngày. Mặc dù dự án có một cơ sở mã khổng lồ, nó không phải là không thể để gỡ lỗi Go, miễn là chúng ta có một phương pháp thích hợp và một số kiến thức về thư viện tiêu chuẩn của Go, chúng ta có thể gỡ lỗi Go, chúng ta sẽ giới thiệu một số phương pháp biên dịch và gỡ lỗi Go ở đây.
1. Biên dịch mã nguồn
Giả sử chúng ta muốn sửa đổi phương pháp phổ biến trong Go fmt.Println
cho phép thực hiện các chức năng như sau: in chuỗi bất kỳ khác trước khi in chuỗi cần in. Chúng ta có thể sửa đổi việc thực hiện phương pháp này thành các đoạn mã như sau, trong đó println
là một phương pháp tích hợp được cung cấp trong thời gian chạy Go, mà không cần phải dựa vào bất kỳ gói nào để in chuỗi sang tiêu chuẩn:
Khi chúng ta sửa đổi dự án mã nguồn cho Go, bạn có thể sử dụng các tập lệnh được cung cấp trong kho để biên dịch và sinh ra Golang binary code và các toolchain liên quan:
Script ./src/make.bash
biên dịch Golang binary, toolchain, standard library và command và di chuyển mã nguồn và các tệp nhị phân được biên dịch đến vị trí tương ứng. Như được hiển thị trong mã trên, binary code được lưu trữ trong thư mục $GOPATH/src/github.com/golang/go/bin
, đây là nơi bạn cần truy cập đường dẫn tuyệt đối và sử dụng :
chúng ta sẽ thấy rằng lệnh trên đã gọi thành công fmt.Println
đã được sửa, và tại thời điểm này, nếu bạn trực tiếp sử dụng go run main.go
, có khả năng sử dụng go
binary code được cài đặt bởi trình quản lý gói mà không nhận được kết quả mong muốn.
2. Intermediate code
Các ứng dụng Go cần phải được biên dịch thành mã nhị phân (binary code) trước khi chạy, trong quá trình biên dịch sẽ trải qua giai đoạn tạo mã trung gian , mã trung gian của trình biên dịch Go có các tính năng của gán giá trị đơn giản tĩnh (Static Single Assignment, SSA), chúng ta sẽ giới thiệu tính năng này của mã trung gian sau này, ở đây chúng ta chỉ cần biết đây là một đại diện của mã trung gian.
Nhiều nhà phát triển Go biết rằng chúng ta có thể biên dịch mã nguồn của Go thành ngôn ngữ assembly bằng cách sử dụng các lệnh sau đây và sau đó thực hiện các quy trình cụ thể bằng cách phân tích ngôn ngữ assembly:
Tuy nhiên, assembly code ở trên chỉ là kết quả của việc biên dịch Go, và là Go developer, chúng ta đã có thể phân tích các nút thắt cổ chai hiệu suất của chương trình thông qua kết quả được mô tả ở trên, nhưng nếu chúng ta muốn hiểu chi sâu hơn quá trình biên dịch của Go, chúng ta có thể dùng lệnh sau để nhận được quá trình tối ưu hóa assembly instruction thông qua :
Lệnh trên tạo ra một tập tin ssa.html
trong thư mục hiện tại, và khi chúng ta mở nó, chúng ta sẽ thấy từng bước của tối ưu hóa assembly code:
Các tệp HTML ở trên có thể tương tác và khi chúng ta click vào assembly instruction trên trang web, trang sẽ sử dụng cùng một màu sắc để xác định các dòng mã có liên quan ở các giai đoạn khác nhau của việc tạo mã trung gian SSA, làm cho nó dễ dàng hơn cho các nhà phát triển để phân tích quá trình tối ưu hóa biên dịch.
3. Nút thắt cổ chai
Nắm vững các phương pháp gỡ lỗi và tùy chỉnh mã nhị phân ngôn ngữ Go có thể giúp chúng ta nhanh chóng xác minh phỏng đoán về việc thực hiện bên trong ngôn ngữ Go, với chức năng println
đơn giản và thô bạo nhất có thể gỡ lỗi mã nguồn và thư viện tiêu chuẩn của ngôn ngữ Go; Và nếu chúng ta muốn nghiên cứu quá trình tối ưu hóa biên dịch chi tiết của mã nguồn, chúng ta có thể sử dụng mã trung gian SSA được đề cập ở trên để đi sâu vào mã trung gian của ngôn ngữ Go và cách tối ưu hóa biên dịch, nhưng đọc mã nguồn là một quá trình không thể tránh khỏi miễn là chúng ta muốn hiểu cách thực hiện ngôn ngữ Go.