Async/await trên GPU
Lập trình đồng thời trên GPU
Lập trình GPU truyền thống tập trung vào song song dữ liệu, nơi một tác vụ được thực hiện đồng thời trên nhiều phần khác nhau của dữ liệu.
fn conceptual_gpu_kernel(data) {
// Tất cả các luồng làm việc đồng thời trên các phần khác nhau của dữ liệu
data[thread_id] = data[thread_id] * 2;
}
Khi các chương trình GPU trở nên phức tạp hơn, các nhà phát triển sử dụng warp specialization để giới thiệu các luồng điều khiển phức tạp hơn và hành vi động.
fn conceptual_gpu_kernel(data) {
let communication = ...;
if warp == 0 {
load(data, communication);
} else if warp == 1 {
compute_A(communication);
} else {
compute_B(communication, data);
}
}
Cải thiện lập trình đồng thời trên GPU
Nhiều dự án nhằm cung cấp lợi ích của warp specialization mà không cần quản lý đồng bộ tay. Ví dụ như JAX, Triton và NVIDIA CUDA Tile giúp việc quản lý và tối ưu hóa thực thi dễ dàng hơn với mô hình lập trình cấp cao.
Nhược điểm của các cách tiếp cận hiện tại
- Các cách tiếp cận cấp cao yêu cầu cấu trúc mã theo những cách mới, khó áp dụng rộng rãi.
- Không hỗ trợ mã CPU hiện tại và thư viện GPU.
Rust’s Future và async/await
Rust cung cấp Future và async/await như một trừu tượng hóa, không yêu cầu một mô hình thực thi cụ thể.
async fn async_double(x: i32) -> i32 {
x * 2
}
Khả năng này cho phép mã async/await chạy trên cả CPU và GPU mà không cần thay đổi cú pháp.
Thực thi trên GPU
Rust không bao gồm trình thực thi sẵn có, đòi hỏi bên thứ ba cung cấp. Ví dụ sử dụng block_on đơn giản để chứng minh khả năng chạy.
Nhược điểm của async/await trên GPU
- Futures là hợp tác, nếu không nhả sẽ gây đói công việc khác.
- Không có cơ chế ngắt, đòi hỏi polling liên tục.
- Sử dụng futures tăng áp lực registro, ảnh hưởng hiệu suất.
Công việc tương lai
Một số executor đang được phát triển dành riêng cho GPU, nhằm tối ưu hóa khả năng đồng thời và hiệu suất.
VectorWare đang thử nghiệm các cách tiếp cận khác nhau để tận dụng sức mạnh GPU một cách tối ưu nhất.