Tương lai của việc tạo tiến trình trong Linux: Vượt qua mô hình fork() + exec()

Phần mềm06 tháng 6, 2026·4 phút đọc

Linux kernel đang tìm kiếm giải pháp thay thế cho cơ chế tạo tiến trình truyền thống fork() và exec() do hiệu suất chưa tối ưu. Mặc dù đề xuất về "spawn templates" gần đây không được chấp nhận, cộng đồng đang hướng tới việc xây dựng một API mới dựa trên pidfd để hiện thực hóa chuẩn posix_spawn() hiệu quả hơn.

Từ những ngày đầu tiên của Unix, hai cuộc gọi hệ thống (system call) cốt lõi để quản lý tiến trình là fork() – tạo ra một tiến trình con là bản sao của tiến trình cha, và exec() – chạy một chương trình mới thay thế cho tiến trình hiện tại. Trong nhân Linux, các cuộc gọi này được biết đến nhiều hơn với tên clone()execve(), nhưng chức năng cốt lõi vẫn giữ nguyên. Mặc dù mô hình này có tính elegan (tinh tế), nó cũng tồn tại những hạn chế lớn về hiệu suất.

Gần đây, một đề xuất từ Li Chen về việc thêm "spawn templates" (mẫu tạo tiến trình) vào nhân Linux đã tạo ra nhiều thảo luận. Dù đề xuất này sẽ không được chấp nhận ở dạng hiện tại, nó có thể chỉ ra hướng đi cho một nguyên thủy (primitive) tạo tiến trình mới trong tương lai.

Hạn chế của fork() và exec()

fork() là một cuộc gọi hệ thống tốn kém về chi phí; nó phải sao chép toàn bộ trạng thái của tiến trình (bao gồm cả bộ nhớ) cho tiến trình con. Qua nhiều năm, đã có nhiều tối ưu hóa được thực hiện, nhưng việc fork vẫn là một thao tác đắt đỏ. Điều tồi tệ hơn là một cuộc gọi fork() thường được theo sau ngay lập tức bởi exec(), sẽ loại bỏ tất cả bộ nhớ vừa được sao chép tốn công đó. Các nỗ lực tối ưu hóa cho trường hợp này (như vfork()) đã tồn tại, nhưng mô hình này vẫn tốn chi phí hơn mức cần thiết.

Đề xuất về Spawn Templates

Tập bản vá (patch set) của Chen tiếp cận vấn đề tối ưu hóa mô hình fork() + exec() theo một hướng thú vị. Nó tập trung vào các ứng dụng thường xuyên khởi chạy các tiến trình chạy cùng một tệp thực thi; ví dụ, một chương trình cần chạy Git nhiều lần để lấy thông tin về kho chứa. Trong những trường hợp như vậy, chương trình có thể thiết lập một khuôn mẫu để tăng tốc các lần gọi này, phân bổ chi phí thiết lập cho nhiều thao tác.

Khuôn mẫu này sẽ được tạo bằng cuộc gọi hệ thống spawn_template_create():

struct spawn_template_create_args {
    __aligned_u64 flags;
    __s32 execfd;
    __u32 exec_flags;
    __aligned_u64 filename;
    /* Một số trường bị lược bỏ */
};
int spawn_template_create(struct spawn_template_create_args *args, size_t args_size);

Cuộc gọi này trả về một file descriptor đại diện cho khuôn mẫu của tệp thực thi. Để tạo khuôn mẫu, nhân sẽ mở tệp được chỉ định và lưu vào bộ nhớ đệm một loạt thông tin giúp quá trình chạy tệp đó nhanh hơn trong tương lai.

Để chạy tiến trình cụ thể, các tham số chi tiết được đặt vào cấu trúc spawn_template_spawn_args, bao gồm đối số (argv), biến môi trường (envp), và các hành động thay đổi file descriptor hoặc xử lý tín hiệu thông qua mảng spawn_template_action.

Khi cấu trúc dữ liệu đã được điền đầy đủ, tiến trình mới được chạy bằng:

int spawn_template_spawn(int template_fd,
                         struct spawn_template_spawn_args *args, int args_size);

Về mặt nội bộ, cuộc gọi hệ thống này tuân theo đường dẫn tương tự như fork()/exec() bình thường, nhưng thông tin được lưu trong khuôn mẫu giúp整个过程 nhanh hơn. Kết quả benchmark cho thấy sự cải thiện khoảng 2%, có vẻ không nhiều, nhưng lại có ý nghĩa đối với các ứng dụng phù hợp với mô hình này.

Hướng tới posix_spawn() và sự thay đổi về API

Đánh giá chi tiết nhất về công việc này thuộc về Mateusz Guzik, người cho rằng: "Toàn bộ thành ngữ fork + exec là khủng khiếp và cần bị loại bỏ". Ông chỉ ra rằng tập trung vào giải pháp của Chen lại bỏ qua phần tốn kém nhất của vấn đề là fork(). Thay vì sao chép tiến trình hiện tại, ông cho rằng "tạo ra một tiến trình sạch (pristine process) mới là cách làm đúng đắn".

Christian Brauner cũng ủng hộ mục tiêu này nhưng đề xuất một cách tiếp cận khác. Ông cho rằng một API mới nên được xây dựng dựa trên sự trừu tượng hóa pidfd (process file descriptor) hiện có. Cách tiếp cận đúng đắn sẽ là tạo một tùy chọn cho pidfd_open() để tạo ra một tiến trình rỗng. Sau đó, một loạt cuộc gọi đến hệ thống mới pidfd_config() sẽ cấu hình tiến trình này theo mong muốn, thiết lập môi trường, hình ảnh thực thi, v.v. pidfd_config() sẽ tương tự như fsconfig().

Một mục tiêu quan trọng của giao diện mới này là khả năng hỗ trợ việc triển khai posix_spawn() trong không gian người dùng (user space). Các nhà phát triển sẽ chào đón một triển khai gốc không phải ẩn giấu fork()exec() bên dưới như hiện tại.

Li Chen đã đồng ý rằng API được phác thảo bởi Brauner có vẻ tốt hơn và cho biết các công việc trong tương lai sẽ đi theo hướng đó. Do đó, sẽ không có "spawn templates" trong nhân Linux, nhưng nếu công việc của Chen thành công, Linux có thể cuối cùng sẽ có một triển khai posix_spawn() phù hợp thay thế cho mô hình cũ kỹ.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗