Chương trình Erlang tôi yêu thích nhất (2013)
(joearms.github.io)- Chỉ với phạm vi ghi chú được cung cấp, không thể xác định chương trình Erlang trong tiêu đề là gì hoặc vì sao nó quan trọng
- Phần văn bản có thể xác nhận chủ yếu chỉ gồm một đoạn script Shell và một câu đính chính ngắn
- Script duyệt qua các tệp
*.png.png.metatrong thư mục hiện tại và trích xuất phần trước dấu chấm đầu tiên từ tên tệp - Lệnh thực sự được chạy là
git mv $i $j.png.meta, còn lệnh đổi$j.png.pngthành$j.pngchỉ được in ra - Do các đoạn gốc 5-104 bị lược bỏ, không thể xác nhận lập luận cốt lõi liên quan đến tiêu đề hoặc phần giải thích mã Erlang
Nội dung có thể xác nhận
- Chỉ với phạm vi được cung cấp, rất khó xác định “chương trình Erlang yêu thích nhất” thực chất là gì, lý do yêu thích hay cấu trúc mã của nó
- Đoạn mã có thể xác nhận là script Shell để đổi tên tệp bắt đầu bằng
#!/bin/sh- Lặp qua các tệp
*.png.png.meta - Dùng
j="${i%%.*}"để lấy phần trước dấu chấm đầu tiên trong tên tệp git mv $i $j.png.metađược thực thi thậtgit mv $j.png.png $j.pngchỉ được in ra bằngecho
- Lặp qua các tệp
- Có câu “Actually you don't need the really do this. It should have been water the plants.”, có thể hiểu là một đính chính rằng chỉ dẫn hoặc ví dụ trước đó thực ra không cần thiết và lẽ ra phải là “water the plants”
- Ở cuối có nhắc cùng lúc đến Joe Armstrong và Jeremy Ruston
Bối cảnh làm hạn chế việc đánh giá
- Nhiều đoạn gồm metadata trạng thái/sidebar của TiddlyWiki, dữ liệu Base64 trông như JPEG/PNG và nội dung rỗng, nên khó trích xuất dữ kiện từ phần thân bài
- Ghi chú được cung cấp không chứa thông tin cốt lõi như cách chương trình Erlang hoạt động, mã, lý do thiết kế, ví dụ, con số, quy trình làm việc hay các lập luận
- Ngay cả đoạn script Shell cũng chỉ được cung cấp một phần, không có giải thích xung quanh nên không thể khẳng định nó thuộc công việc nào
Phạm vi bị lược bỏ
- Đầu vào ghi rõ rằng các đoạn gốc 5-104 đã bị lược bỏ do giới hạn độ dài/chi phí
- Bản tóm lược này chỉ phản ánh phạm vi ghi chú đã được cung cấp và không bao quát toàn bộ chi tiết hay kết luận của nguyên văn
1 bình luận
Các ý kiến trên Hacker News
Nếu closure máy chủ
Fngoài thông điệp của chính nó còn có thể nhận thông điệp{become, F}, thì có thể liên tục biến máy chủ thành hành vi mớiChuyện hơi khác, nhưng tôi vẫn nhớ lần nói chuyện với Joe tại một hội nghị Erlang. Ông luôn hào hứng với công nghệ và sẵn lòng trò chuyện với bất kỳ ai. Ông tiếc rằng Windows mỗi năm lại tệ hơn và kém hữu dụng hơn, và nói rằng một ngày nào đó muốn xem tệp thì phải xem quảng cáo một lúc mới được mở khóa — giờ gần như đúng rồi. Windows 11 đã có quảng cáo, muốn gỡ thì phải cố tình lục tìm trong phần cài đặt, nên đến khoảng Windows 13 có lẽ thật sự sẽ như vậy
Chẳng hạn âm lượng một bên tai nghe lớn hơn hẳn, ứng dụng Microsoft bị crash một cách kỳ lạ, trang tài liệu Windows không mở được trên bất kỳ trình duyệt nào nên phải dùng trang lưu trữ, màn hình ngoài trước vẫn nhận tốt bỗng nhiên không nhận hoặc nhấp nháy. Office mặc định thúc người dùng lưu lên cloud thay vì lưu cục bộ, nhưng tôi nghiêng về phía tệp nên ưu tiên cục bộ, còn cloud chỉ nên là sao lưu. WSL khá cẩu thả, nhưng ít nhất nó gần như là lý do duy nhất khiến tôi còn dùng được Windows
Tôi luôn nghe nói Joe là một người tuyệt vời và thấy điều đó hoàn toàn hợp lý. Khi mới tự học lập trình, tôi đọc sách Erlang của ông; sự tinh nghịch, khiêm nhường và trí tưởng tượng trong đó ảnh hưởng rất lớn đến tôi. Dù rốt cuộc hầu như không dùng Erlang, các bài viết của ông đã thay đổi cách tôi suy nghĩ về code, và tôi mong văn hóa toán học, kỹ nghệ phần mềm và khoa học máy tính sẽ đón nhận nhiều hơn sự tinh nghịch và khiêm nhường
Một video tổng quan ngắn 35 phút giải thích vì sao BEAM khác với các máy ảo khác như JVM hay Node: https://www.youtube.com/watch?v=pO4_Wlq8JeI
Nhớ Joe. Niềm đam mê có sức lan tỏa của ông trong việc làm cho điện toán tốt hơn đã in sâu vào con người tôi thời trẻ và cả cách tôi tiếp cận công nghệ hiện nay
universal_server() -> receive {become, F} -> F() end.Thành thật mà nói, tôi chưa hoàn toàn hiểu sức mạnh của universal_server này. Mong ai đó giải thích giúp
Trong Erlang, người ta khởi chạy nhiều process để giải quyết vấn đề, và hầu hết process đều chờ thông điệp. Điểm khác biệt quan trọng là process Erlang có thể chạy mượt mà cả trên máy từ xa. Process này nhận một thông điệp dạng tuple chứa atom
becomevà một hàm; bất kỳ process nào khác gửi thông điệp đó vào lúc nào cũng có thể khiến nó “biến thành” hàm đóTức là bạn có thể thay logic của vòng lặp chờ bằng logic giao thức mong muốn. Trong ví dụ, họ khởi chạy vòng lặp này trên nhiều máy rồi gửi một hàm triển khai gossip protocol, nhưng cũng có thể gửi một thông điệp khiến nó trở thành một client BitTorrent. Joe vừa là thiên tài vừa là một người rất tử tế, và Erlang là một trong những sáng tạo kỹ thuật đẹp nhất tôi từng thấy. Nó khiến tôi nhìn concurrency theo một cách hoàn toàn mới
receivegiống như câu lệnhswitchcho các thông điệp đến, nhưng thực chất là pattern matchingVí dụ, có thể tạo một máy chủ tính giai thừa nhận
{From, N}rồi trả kết quả bằngFrom ! factorial(N).!là toán tử gửi kết quả đến process trả vềMã kiểm thử khởi chạy
universal_server, dùngPid ! {become, fun factorial_server/0}để biến nó thành máy chủ tính giai thừa, rồi gửi{self(), 50}để nhận lại giai thừa của 50. Lợi thế lớn của Erlang là song song phân tán và hot code update, và ở đây nó thể hiện dưới dạng ghi đè vòng lặp nhận củauniversal_serverbằng vòng lặp nhận củafactorial_server. Tuy vậy, tôi nghĩ hot code update thực tế không hoạt động chính xác theo cách nàyNhưng trong Erlang, bạn có thể tạo một mạng lưới máy chủ Erlang phân tán và để các máy chủ như tài nguyên tính toán đa dụng có thể làm việc mà client muốn. Code đến từ client; không cần nhờ quản trị hệ thống cài binary lên mọi máy, chỉ cần truyền hàm và máy từ xa sẽ gọi nó
Hàm thực sự chạy máy chủ do client truyền vào, và process Erlang dựa trên hàm đó để trở thành máy chủ tương ứng. Nếu tính cả khả năng hot reloading của Erlang, cấu trúc đơn giản này trở nên mạnh mẽ hơn. Có thể xem process Erlang là tài nguyên tính toán đang chờ việc, và nếu việc đó là chạy một máy chủ hoàn chỉnh thì cũng khá tuyệt
Vì vậy process có thể trở thành bất cứ thứ gì tùy theo code bạn gửi. Nếu nó đang điều khiển lò vi sóng, rồi cần thực hiện tính toán lượng tử, và hôm sau dự đoán đội thắng trận bóng đá, thì chỉ cần gửi code cần cho từng tác vụ là nó sẽ thực hiện đúng như vậy
Tôi đã mất rất nhiều thời gian để giải thích vì sao BEAM đặc biệt, và vì sao concurrency của Erlang/Elixir khác với concurrency của Go hay Java
Từ giờ có lẽ chỉ cần gửi liên kết đến chương trình Erlang mà Joe thích nhất và thread HN này
Bài blog này cũng được đề cập trong một bài thuyết trình xuất sắc gần đây: https://youtu.be/pQ0CvjAJXz4
Tôi chỉ có hiểu biết ở mức cao về ngôn ngữ Erlang chứ chưa từng trực tiếp lập trình bằng nó, nên tò mò vì sao đoạn code này lại cần thiết
universal_server() -> receive {become, F} -> F() end.Tôi nghĩ chẳng phải cứ chạy trực tiếp
F()trên máy từ xa là được sao. Vì máy ảo từ xa hẳn đã phải có sẵn code củaF, nên ví dụ này cũng có thể có nghĩa là tuần tự hóa code củaFrồi truyền đi. Nếu nó xử lý boilerplate chung thì tôi hiểu được tính hữu ích, nhưng hiện tại trông như chỉ đợi thông điệpbecome Frồi thực thiF()Ở đây
Flà closure, nên không chỉ có code mà còn có thể bao gồm các biến đã capture và môi trường tại thời điểm nó được tạo. Khi gọiF(), code đó sẽ được thực thi và có thể truy cập môi trường xung quanh lúcFđược tạoTrong Erlang, có thể gửi closure qua mạng sang một node Erlang khác. Tuy nhiên, code module mà closure tham chiếu phải có trên tất cả các node. Với code vận hành thực tế, như bạn nói, nhiều khả năng sẽ gọi trực tiếp module
Fvà truyền đối số một cách tường minh; còn đây gần với một màn demo thú vị để cho thấy khả năng đóF()có thể trở thành ngữ cảnh cấp cao nhất tốt như bất kỳ ngữ cảnh nào trước đó, điều này rất hayCó thể để các request hiện có được xử lý tự nhiên bằng logic cũ, trong khi request mới bắt đầu bằng logic mới, và cuối cùng logic cũ có thể được garbage collect
F, nhưng cũng có thể gửi code sang máy ảo từ xaVí dụ trong Elixir, có thể dùng
Code.compile_stringđể lấy tên module và binary bytecode BEAM. Có thể gửi bytecode đó sang một máy ảo khác, tải nó vào máy ảo từ xa bằng:rpc.call('node@remote_host', :code, :load_binary, [the_module_name, "filename_doesnt_really_matter", binary_code]), rồi chạy bằngspawn('node@remote_host', my_module, my_function, [args])Ở đây
Flà biến biểu thị chương trình mới đã được tuần tự hóa và gửi dưới dạng thông điệp giữa các process; trong trường hợp này nó cũng được truyền qua mạngCũng có một bài giảng trong đó Joe giải thích cách viết một server cơ bản bằng Erlang: https://gioorgi.com/2015/erlang-lesson1/
Tôi đã tự chép lại và giải thích thêm một chút; nó cho thấy sức mạnh của các ngôn ngữ bất đồng bộ như Erlang/Elixir so với những ngôn ngữ khác. Tiếc là ngày nay chúng không được dùng nhiều
Gần đây tôi đang mê Julia, và có vẻ nó vay mượn khá nhiều ý tưởng của Erlang trong mô hình phân tán
Những server tức thời hoạt động như phép màu trên nhiều node như thế này cũng có thể được tái hiện khá dễ trong Julia. Tôi không chắc, nhưng khó tin là module
Distributedcủa Julia lại không được Erlang truyền cảm hứng dù chỉ một chútTôi thật sự thích Erlang và ước gì có nhiều cơ hội dùng nó hơn, nhưng cũng rất vui khi thấy các khái niệm đó thấm sang những nền tảng khác