Hacker News Nổi bật (buzzing.cc bản dịch tiếng Trung)
85

Sản phẩm

Rust Glancer: Công cụ LSP tối ưu, giảm mức tiêu thụ RAM xuống chỉ còn 1%

(giờ Việt Nam)

Tóm tắt AI

Rust Glancer là giải pháp thay thế LSP cho Rust với mục tiêu tiết kiệm tài nguyên vượt trội, chỉ chiếm 1% bộ nhớ so với rust-analyzer. Dự án được phát triển với sự hỗ trợ của AI và đã sẵn sàng cho nhu cầu sử dụng thực tế.

Bản dịch AI

Tôi muốn giới thiệu một dự án mà tôi đã thực hiện trong 4 tháng qua: một bản triển khai LSP (Language Server Protocol) thay thế cho Rust, được xây dựng với trọng tâm là sử dụng bộ nhớ thấp.

Nó có hai tính năng chính:

Lưu ý: trong suốt video này, lượng RAM sử dụng luôn duy trì dưới 100mb.

Những tính năng này giúp Rust Glancer phù hợp với các máy tính cũ hơn: Tôi đã thử nghiệm nó trên chiếc MacBook Pro M1 2020 cũ của mình với 8GB RAM, và nó hoạt động khá tốt.

Như bạn có thể hình dung, 4 tháng không phải là khoảng thời gian dài cho một dự án lớn như Rust LSP. Rust Glancer vẫn chưa phải là một LSP hoàn chỉnh, nó còn thiếu nhiều chức năng, có một số lỗi đã biết và còn rất nhiều thứ tôi muốn cải thiện.

Đồng thời, nó đã khá mạnh mẽ: nó có một quy trình lập chỉ mục (indexing pipeline) đầy đủ với suy luận kiểu (type inference) và bộ giải trait (chalk), hỗ trợ hầu hết cú pháp Rust "thông thường", và hầu hết các hành động LSP "thông thường" cũng hoạt động tốt: goto definition, hover, inlay hints, completions, bạn cứ kể tên đi.

Nếu bạn quan tâm, bạn đã có thể dùng thử ngay: chỉ cần cài đặt tiện ích mở rộng VS Code tại đây, hoặc nếu muốn, bạn có thể tự build và cài đặt file vsix từ kho lưu trữ.

Phần còn lại của bài viết chứa lịch sử của dự án: động lực, việc sử dụng LLM, các kế hoạch và lộ trình. Nếu bạn không quan tâm, bạn có thể xem tài liệu của dự án thay thế.

Sự khác biệt với rust-analyzer

Có một vài lý do khiến rust-analyzer tiêu tốn nhiều bộ nhớ:

(1) là điều chúng ta phải chấp nhận (mặc dù có một vài tối ưu hóa chúng ta có thể thực hiện ở đó mà Rust Glancer đã làm), nhưng (2) và (3) là hệ quả từ kiến trúc của rust-analyzer. rust-analyzer chọn chúng để làm cho LSP nhanh hơn, và nó thực sự hiệu quả cho mục đích đó.

Ý tưởng tôi có khi bắt đầu dự án là: điều gì sẽ xảy ra nếu chúng ta không cố gắng tạo ra một LSP tăng dần (incremental)? Điều gì sẽ xảy ra nếu tất cả những gì chúng ta có là một kết quả phân tích đóng băng (frozen) và sẽ bị vô hiệu hóa khi lưu file? Rõ ràng nó sẽ không nhanh bằng rust-analyzer, nhưng nó sẽ mang lại cho chúng ta những đặc tính mà chúng ta tìm kiếm:

Đây là ý tưởng cốt lõi của Rust Glancer.

Nó lập chỉ mục không gian làm việc (workspace) một lần và lưu giữ kết quả trong hệ thống tệp, sau đó bất cứ khi nào các truy vấn cần thông tin, chúng có thể tải thông tin cần thiết trong suốt thời gian thực hiện truy vấn.

Tuy nhiên, nó không miễn phí: phân tích không gian làm việc đóng băng theo định nghĩa sẽ chậm hơn so với phân tích tăng dần lười biếng (lazy incremental), vì việc tải và giải mã dữ liệu từ hệ thống tệp chậm hơn so với tải từ bộ nhớ. Để giảm thiểu điều đó, Rust Glancer phải sử dụng một số thủ thuật: ví dụ, khi bạn gõ, nó không thực hiện phân tích toàn diện trên mỗi lần nhấn phím, thay vào đó nó cố gắng phân tích nông (shallow analysis) phần thân hiện tại và tái sử dụng chỉ mục hoàn chỉnh trước đó. Điều này làm cho các gợi ý (completions) nhanh một cách hợp lý, nhưng nó cũng có nghĩa là các mục mới (import, cấu trúc, trait) sẽ không được "lập chỉ mục" cho đến khi bạn lưu tài liệu. Hy vọng rằng đây không phải là vấn đề: bạn sẽ thực sự quen với nó rất nhanh, và ít nhất là trong trường hợp của tôi, nó không cảm thấy quá bất tiện sau một thời gian. Nếu điều đó nghe có vẻ đáng sợ, tôi khuyên bạn chỉ cần dùng thử, nó thực sự không tệ đến thế.

Đối với những người dựa vào quy trình làm việc có tác nhân (agentic workflows), Rust Glancer cũng được tối ưu hóa cho một lượng lớn các thay đổi bên ngoài trình soạn thảo. Tôi không chắc tại sao, nhưng trong rust-analyzer, tôi đã quan sát thấy rằng khi các tác nhân chỉnh sửa mã, các inlay hints có thể bị lệch vị trí, và tôi cũng gặp vấn đề tương tự trong Rust Glancer ban đầu, nhưng nó đã được giải quyết bằng cách triển khai một trình theo dõi tệp tùy chỉnh và tinh chỉnh nó đôi chút. Máy chủ cũng có mức ưu tiên thấp hơn cho các thay đổi bên ngoài trình soạn thảo, vì vậy các thay đổi từ tác nhân không gây ra việc lập chỉ mục lại liên tục.

Tuy nhiên, điều quan trọng cần hiểu là Rust Glancer có một số lợi ích, nhưng cũng có một số nhược điểm (ngoài việc chưa hoàn thiện, rõ ràng là vậy) so với rust-analyzer. Có lẽ cuối cùng tôi sẽ giải quyết được một số trong đó, nhưng rất khó có khả năng Rust Glancer sẽ trở thành "giống hệt rust-analyzer, nhưng tốt hơn". Tôi hình dung rằng rust-analyzer sẽ vẫn là lựa chọn mặc định cho các dự án quan tâm đến sự đầy đủ và độ chính xác khi gõ phím, trong khi Rust Glancer sẽ phù hợp với những người có máy tính yếu hơn hoặc những người sẵn sàng hy sinh một chút để giảm mức sử dụng RAM.

Nó đã xảy ra như thế nào và tại sao

Tôi đã viết Rust chuyên nghiệp được khoảng 7 năm, và từ khá sớm, tôi đã bắt đầu quan sát cách trình biên dịch và các công cụ của nó được phát triển. Tôi đã đóng góp một số phần cho rustc, clippy và rust-analyzer, và tôi đã dành hàng chục giờ để đọc mã nguồn của nó chỉ để tự học. Vì vậy, tôi khá nhận thức được dự án Rust LSP là một dự án lớn đến mức nào.

Đồng thời, tôi có một mối quan hệ yêu-ghét với rust-analyzer. Nó hoàn toàn tuyệt vời ngoại trừ hai điều: mức sử dụng bộ nhớ và lập chỉ mục ban đầu (đặc biệt là khi bật các tập lệnh build / proc macro). Những vấn đề này dường như được nhắc đến khá nhiều, nhưng trong trường hợp của tôi, chúng còn nghiêm trọng hơn: tôi có một quy trình làm việc khá ngớ ngẩn là mở hai IDE giống hệt nhau trên hai màn hình với một loạt các dự án bên trong một không gian làm việc. Vì vậy, mức tiêu thụ bộ nhớ là khoảng 2N, và với bộ dự án cuối cùng mà tôi phải làm việc, rust-analyzer đã tiêu tốn 16GB bộ nhớ mà tôi, ôi, muốn dành cho các mục đích khác; chưa kể mỗi khi tôi mở VS Code, quạt PC của tôi lại kêu vù vù vì hàng tấn công việc lập chỉ mục song song.

Tại một thời điểm, tôi nghĩ rằng mình khá tự tin vào kiến thức Rust của mình, vì vậy tôi có lẽ không cần một LSP đầy đủ, và có thể sử dụng thứ gì đó đơn giản hơn và tiết kiệm bộ nhớ hơn. Tôi quyết định thử xây dựng một "ctags thông minh cho Rust". Tôi rất rõ ràng là không muốn xây dựng một LSP thay thế, vì đó là một nhiệm vụ điên rồ. Tôi đâu có biết...

Tiến trình ban đầu diễn ra khá suôn sẻ: tôi đã sử dụng thư viện cú pháp của rust-analyzer, hạ cấp các mục xuống các biểu diễn nội bộ, sau đó xây dựng bản đồ định nghĩa và cấu trúc mô-đun, lập chỉ mục tất cả các khai báo. Nó đáng ngạc nhiên là đơn giản đến mức tôi quyết định thực hiện một số việc hạ cấp phần thân (body lowering) sơ khai. Sau đó, tôi quyết định thêm tính năng truyền kiểu (type propagation) rất rất đơn giản. Sau đó, hóa ra việc truyền kiểu ngây thơ không mang lại nhiều kết quả - nhưng tôi đã có những inlay hints tuyệt vời này, vì vậy tôi muốn nhiều hơn nữa. Nhìn chung, tôi không quan tâm đến các trường hợp phức tạp và các tính năng nightly, phải không? (Phải không?...). Vì vậy, sau đó là việc giải quyết trait ngây thơ thông qua so khớp tiêu đề impl. Nó khá gây nghiện, bạn hiểu mà.

Tuy nhiên, ảo tưởng đã tan vỡ khi tôi quyết định rằng việc mong đợi đoạn mã sau đây cũng được hỗ trợ là khá hợp lý:

Mã này khá đơn giản, nhưng để hỗ trợ nó, chúng ta cần:

Mục cuối cùng thật buồn cười: tôi muốn tránh dùng nightly, nhưng bằng cách nào đó tôi đã không nghĩ rằng std (hoặc sysroot nói chung) lại "thở" bằng nightly. Chà.

Vì vậy, tóm lại, hết tính năng này đến tính năng khác, tôi dần dần chuyển từ "ctags thông minh" sang một "LSP thực thụ". Có lẽ, ba cột mốc lớn nhất là:

Một cách riêng biệt, có lẽ điều tôi tự hào nhất (và là điều làm cho Rust Glancer trở nên khả thi - nếu tôi không thiết kế nó sớm, dự án sẽ chết rất nhanh) là một ngăn xếp profiling tuyệt vời có thể đo lường hiệu suất, mức sử dụng bộ nhớ (cả nguyên bản, theo dõi các đối tượng được cấp phát thực tế, và với jemalloc), dữ liệu profile theo yêu cầu, và so sánh LSP với rust-analyzer, cũng như một bộ benchmark chạy trong CI. Nếu bạn quan tâm, nó được đề cập một phần trong tài liệu (1, 2), nhưng tôi sẽ làm việc trên một phạm vi chi tiết hơn sau.

Có lẽ khoảng 1,5 tháng trước, tôi bắt đầu sử dụng Rust Glancer làm công cụ chính hàng ngày thay vì rust-analyzer. Bây giờ, tôi đủ hài lòng với trạng thái của nó để giới thiệu nó đến với nhiều người hơn.

Sử dụng LLM

Dự án này được xây dựng với việc sử dụng nhiều LLM. Tuy nhiên, nó không phải là "vibe coded" (viết mã theo cảm tính). Tôi đang xác minh từng pull request để đảm bảo rằng tôi hài lòng với trạng thái của cơ sở mã. Nếu bạn cần bằng chứng, bạn có thể kiểm tra lịch sử git: nó có các PR với hơn 10k dòng diff, nhưng chúng cách nhau nhiều ngày mặc dù thực tế là tôi làm việc trên dự án này gần như mỗi ngày kể từ khi nó bắt đầu. Tôi quan tâm đến mã nguồn, và thành thật mà nói, sẽ thật kỳ lạ nếu tôi dành 4 tháng để tạo ra một Rust LSP mà việc xem mã nguồn không phải là thứ tôi làm thường xuyên.

Tôi sẽ không giả vờ rằng mình là một nhà phát triển LSP có kinh nghiệm và mã nguồn là hoàn hảo. Nó đang ở trạng thái mà tôi có thể làm việc được, nhưng tôi hiểu rằng một số phần có thể không thành thạo (idiomatic) về mặt thiết kế công cụ trình biên dịch. Mã nguồn có rất nhiều bình luận, và tôi đã cố gắng hết sức để đảm bảo rằng những bình luận này không cẩu thả mà hữu ích, vì tôi phải đọc chúng mọi lúc; cho đến nay chất lượng rõ ràng không tốt bằng các tài liệu do con người viết chuyên nghiệp, nhưng theo ý kiến của tôi, nó khá hữu ích và không gây khó chịu khi đọc.

Một phần lớn của hành trình là học hỏi. LLM có thể là những chuyên gia lĩnh vực khá giỏi, và LLM biết về thiết kế LSP nhiều hơn tôi. Đồng thời, LLM không giỏi trong việc xây dựng các dự án lớn. Vì vậy, vòng lặp sau đây đã xảy ra nhiều lần trong quá trình phát triển:

Vì vậy, một mặt, nếu tôi gán quyền sở hữu mã cho LLM, tôi có thể phàn nàn: "LLM đã cố gắng làm chệch hướng dự án rất nhiều lần!". Nhưng vì đó là mã của tôi, tôi nghĩ rằng mã có thể trở nên tồi tệ hơn ở một số thời điểm, nhưng khi tôi học, tôi có thể cải thiện nó. Đó là quy trình phát triển phần mềm khá bình thường, chỉ là được tăng tốc.

Tóm lại, LLM chỉ là một công cụ, và việc sử dụng nó một cách có trách nhiệm hay thuê ngoài tư duy cho nó là lựa chọn của mỗi người. Với số lượng các cuộc săn phù thủy ngày nay, tôi chỉ có một yêu cầu: đừng hạ thấp tôi thành một kẻ lạm dụng AI. Đó là mã của tôi, vì vậy nếu bạn coi đó là rác, hãy gọi đó là rác của tôi, không phải AI.

Tôi cởi mở với những lời chỉ trích và sẽ vui vẻ lắng nghe phản hồi: càng học hỏi nhiều, tôi càng có thể cải thiện cơ sở mã. Theo tôi, việc tôi có sử dụng LLM cho việc đó hay không không quan trọng lắm.

Tiếp theo là gì

Dự án đã ở trạng thái có thể là công cụ hàng ngày cho một số người dùng, nhưng tôi có những kế hoạch khá lớn cho nó. Vì vậy, trong các bản phát hành sắp tới, bạn có thể mong đợi:

Tuy nhiên, một số tính năng khó có khả năng được hỗ trợ, chẳng hạn như hỗ trợ tập lệnh build / proc macro thông qua việc gọi proc macro (ví dụ: bất cứ thứ gì yêu cầu thực thi mã không đáng tin cậy). Tôi cũng không có kế hoạch làm việc trên những thứ không cần thiết ở trạng thái hiện tại của dự án, chẳng hạn như di chuyển sang bộ giải trait mới. Những thứ ngách như các tính năng nightly cụ thể có thể sẽ bị hoãn lại cho đến khi dự án đạt được một mức độ trưởng thành nhất định với Rust ổn định.

Ngoài ra, có rất nhiều thủ thuật nhỏ thú vị mà tôi đã thực hiện trong Rust Glancer mà tôi khá tự hào (căn chỉnh thời gian sống của cấp phát để giảm phân mảnh bộ nhớ, mô hình engine-as-a-subprocess để giúp ích cho cả việc phân mảnh bộ nhớ và các dự án đa không gian làm việc, bộ nhớ đệm phân đoạn, và những thứ khác), vì vậy nếu mọi người quan tâm, tôi sẽ rất vui khi viết một số blog kể về cách Rust Glancer hoạt động dưới nắp ca-pô. Nó đã được đề cập một phần trong tài liệu (1, 2) nếu bạn muốn biết thêm thông tin ngay bây giờ.

Nhưng dù sao đi nữa, tôi hy vọng rằng dự án có thể hữu ích cho một số người ngay bây giờ, và cho nhiều người hơn nữa trong tương lai.

Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ Hacker News Nổi bật (buzzing.cc bản dịch tiếng Trung). Liên kết bài gốc ở phía trên. Dữ liệu đồng bộ qua API công khai được ghi nguồn tại AI HOT (canonical) ↗. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.