Bạn cần bao nhiêu bộ nhớ trong năm 2024 để chạy 1 triệu tác vụ đồng thời?
(hez2010.github.io)Đã chạy các chương trình xử lý 1 triệu tác vụ đồng thời bằng các phiên bản mới nhất của Rust, C#, Python, Go, Java, NodeJS để so sánh hiệu quả sử dụng bộ nhớ.
C# (NativeAOT) và Rust cho thấy hiệu quả bộ nhớ tốt nhất, trong khi Go bị đánh giá thấp vì mức tiêu thụ bộ nhớ cao hơn kỳ vọng. Nhìn chung, hiệu năng của .NET và Rust nổi bật, còn Java (GraalVM) cho thấy sự cải thiện đáng kinh ngạc.
Cụ thể, Rust sử dụng ít bộ nhớ nhất với khoảng 29MB, tiếp theo là C# NativeAOT với khoảng 71MB. NodeJS ghi nhận 232MB, Python là 339MB. Go đạt 753MB, cho thấy mức sử dụng bộ nhớ tương đối cao và mang lại kết quả đáng tiếc. Java (GraalVM) đạt 92MB, cho thấy sự cải thiện lớn.
10 bình luận
Nhìn vào mã benchmark, có vẻ như trong trường hợp của Rust và Python, thực tế không phải là tạo ra concurrent task, mà chỉ tạo ra các đối tượng future tuy bất đồng bộ nhưng không thể chạy song song với các task khác. Có lẽ C# cũng là trường hợp tương tự. Ngược lại, mã Go lại tạo ra goroutine là một task tự có call stack riêng, nên tôi nghĩ nguyên nhân khiến mức sử dụng bộ nhớ của Go đặc biệt vọt lên trong trường hợp 1 triệu là nằm ở đây.
Để bênh vực cho Go thì, Go vẫn chạy được ngay cả khi trong 1 triệu hàm đang chạy có dùng bất kỳ thư viện nào. Chỉ cần thêm
govào là được. Ở các ngôn ngữ khác dựa trên bất đồng bộ, nếu ở giữa có một thư viện theo kiểu đồng bộ ngốn chút thời gian thì sẽ rơi vào tình huống điên đầu là nó nuốt sạch mọi lợi thế của bất đồng bộ. Để tận dụng 100% lợi thế của bất đồng bộ thì mọi hàm dù chỉ tốn chút thời gian cũng đều phải đổi sang bất đồng bộ. Còn Java VirtualThread thì ừm... lần này ở công ty chúng tôi đã tin vào Java VirtualThread để triển khai, nhưng cuối cùng vì vấn đề tương thích thư viện nên lại phải đổi sang thread thường, và kết cục là phải bật hàng chục instance.Có thể nói thêm một chút về phần tương thích được không :eyes:
Có thể nói là giờ đây không còn đúng câu kiểu như trong Spring, "muốn dùng WebFlux cho ra đúng chất thì phải dùng cùng R2DBC thay vì JPA mới phát huy được giá trị thật sự" nữa.
Tôi nghe nói thư viện msal của MS không hoạt động trên virtual thread
Tôi nghĩ thư viện
msalmà bạn nêu làm ví dụ cũng là trường hợp tương tự trong Go, nếu đó là thư viện sử dụng kiểu dữ liệu hoặc cấu trúc không thread-safe.Điều đó có liên quan gì đến thread safety? Ngay từ đầu,
goroutineđâu phải là một hệ thống bảo đảm thread safety.Cảm ơn bạn đã chia sẻ thông tin.
Tôi có một câu hỏi muốn hỏi.
Vậy thì với các ngôn ngữ khác ngoài Go, nếu có thư viện hoạt động theo kiểu đồng bộ như bạn nói thì đều sẽ bị phá vỡ hết sao?
Hay là trong số các ngôn ngữ khác cũng có ngôn ngữ nào hỗ trợ bất đồng bộ hoàn chỉnh như Go không, tôi khá tò mò.
Có một cách diễn đạt là
colorless. Go là ngôn ngữ duy nhất không cần phải phân biệt giữa bất đồng bộ và đồng bộ. Từ góc nhìn của người dùng, khi lập trình cần đến tính đồng thời, Go có ưu thế áp đảo về độ khó và tính dễ sử dụng.Dĩ nhiên, về hiệu năng thì nó có thể kém hơn một chút so với lập trình bất đồng bộ được tối ưu hóa.
Xin lỗi vì bắt bẻ, nhưng tôi chỉ xin nói về những chỗ chưa đúng trong cách diễn đạt "bị vỡ" và "bất đồng bộ hoàn hảo". Với bất đồng bộ thì dùng thư viện kiểu đồng bộ vẫn không sao, miễn là có đảm bảo sẽ hoàn thành trong thời gian ngắn. Vấn đề phát sinh khi có lời gọi chạy lâu theo kiểu đồng bộ, vì nó làm chậm việc xử lý các tác vụ bất đồng bộ khác. Go có thể phân bổ đến hàng trăm triệu công việc bằng goroutine, nên bản thân ngôn ngữ không có khái niệm bất đồng bộ. Từ góc độ người dùng thì chỉ cần gọi bất kỳ hàm nào rồi thêm
golà nó sẽ chạy song song, nên cực kỳ tiện. Cá nhân tôi nghĩ "bất đồng bộ hoàn hảo" có lẽ là JavaScript, vì nền tảng cốt lõi của ngôn ngữ này vốn là bất đồng bộ.