Các dự án phần mềm lớn thường bao gồm nhiều đơn vị biên dịch có thể được biên dịch tương đối độc lập và do đó quá trình biên dịch thường được song song hóa ở mức độ chi tiết rất thô bằng cách gọi trình biên dịch nhiều lần song song. Điều này xảy ra ở cấp độ của các quy trình HĐH và được điều phối bởi hệ thống xây dựng chứ không phải trình biên dịch thích hợp. Tôi nhận ra đây không phải là những gì bạn yêu cầu nhưng đó là điều gần nhất để song song hóa trong hầu hết các trình biên dịch.
Tại sao vậy? Chà, phần lớn công việc mà các trình biên dịch không tự cho vay để song song hóa một cách dễ dàng:
- Bạn không thể chia đầu vào thành nhiều phần và lex chúng một cách độc lập. Để đơn giản, bạn muốn phân tách trên các ranh giới lexme (để không có luồng nào bắt đầu ở giữa một lexme), nhưng việc xác định ranh giới lexme có khả năng đòi hỏi nhiều bối cảnh. Ví dụ: khi bạn nhảy vào giữa tệp, bạn phải đảm bảo rằng bạn đã không nhảy vào một chuỗi ký tự. Nhưng để kiểm tra điều này, bạn phải xem xét về cơ bản mọi nhân vật xuất hiện trước đây, công việc gần như chỉ đơn giản là bắt đầu với nó. Bên cạnh đó, lexing hiếm khi là nút cổ chai trong trình biên dịch cho các ngôn ngữ hiện đại.
- Phân tích cú pháp thậm chí còn khó hơn để song song. Tất cả các vấn đề về phân tách văn bản đầu vào để từ chối thậm chí còn áp dụng nhiều hơn cho việc phân tách các mã thông báo để phân tích cú pháp --- ví dụ: xác định nơi một chức năng bắt đầu về cơ bản khó như phân tích nội dung chức năng để bắt đầu. Mặc dù cũng có thể có những cách xoay quanh vấn đề này, nhưng có lẽ chúng sẽ phức tạp một cách không cân xứng vì lợi ích nhỏ. Phân tích cú pháp cũng không phải là nút cổ chai lớn nhất.
- Sau khi bạn phân tích cú pháp, bạn thường cần thực hiện phân giải tên, nhưng điều này dẫn đến một mạng lưới các mối quan hệ đan xen rất lớn. Để giải quyết một cuộc gọi phương thức ở đây, trước tiên bạn có thể phải giải quyết các lần nhập trong mô-đun này, nhưng những yêu cầu này phải giải quyết các tên trong một đơn vị biên dịch khác , v.v. Tương tự đối với suy luận kiểu nếu ngôn ngữ của bạn có điều đó.
Sau này, nó trở nên dễ dàng hơn một chút. Về nguyên tắc, việc kiểm tra và tối ưu hóa và tạo mã có thể được song song hóa ở mức độ chi tiết của hàm. Tôi vẫn biết rất ít nếu có bất kỳ trình biên dịch nào làm việc này, có lẽ bởi vì thực hiện bất kỳ nhiệm vụ nào đồng thời lớn này là khá khó khăn. Bạn cũng phải xem xét rằng hầu hết các dự án phần mềm lớn chứa rất nhiều đơn vị biên dịch nên cách tiếp cận "chạy một loạt trình biên dịch" là hoàn toàn đủ để giữ tất cả các lõi của bạn (và trong một số trường hợp, thậm chí là toàn bộ cụm máy chủ). Thêm vào đó, trong các tác vụ biên dịch lớn, I / O của đĩa có thể bị tắc nghẽn nhiều như công việc biên dịch thực tế.
Tất cả những gì đã nói, tôi biết một trình biên dịch song song với công việc tạo và tối ưu hóa mã. Trình biên dịch Rust có thể phân chia công việc phía sau (LLVM, thực sự bao gồm tối ưu hóa mã được coi là "trung cấp" theo truyền thống) giữa một số luồng. Điều này được gọi là "đơn vị mã gen". Ngược lại với các khả năng song song hóa khác được thảo luận ở trên, điều này là kinh tế vì:
- Ngôn ngữ có các đơn vị biên dịch khá lớn (so với C, Java), do đó, có thể có ít đơn vị biên dịch trong chuyến bay hơn so với lõi của bạn.
- Phần đang được song song hóa thường chiếm phần lớn thời gian biên dịch.
- Phần lớn công việc phụ trợ là phần song song, đáng xấu hổ - chỉ cần tối ưu hóa và dịch sang mã máy từng chức năng một cách độc lập. Tất nhiên, có các tối ưu hóa theo thủ tục và các đơn vị codegen cản trở chúng và do đó ảnh hưởng đến hiệu suất, nhưng không có bất kỳ vấn đề ngữ nghĩa nào.