Pony,一種“Rust 遇上 Erlang”的語言,讓開發快捷、安全、高效、高並行的程式更簡單。
在 Wallaroo Labs,我是工程副總裁,我們正在構建一個用 Pony 程式語言編寫的 高效能分散式流處理器。大多數人沒有聽說過 Pony,但它一直是 Wallaroo 的最佳選擇,它也可能成為你的下一個專案的最佳選擇。
“一門程式語言只是另一種工具。與語法無關,與表達性無關,與正規化或模型無關,僅與解決難題有關。” —Sylvan Clebsch,Pony 的建立者
我是 Pony 專案的貢獻者,但在這裡我要談談為什麼 Pony 對於像 Wallaroo 這樣的應用是個好選擇,並分享我使用 Pony 的方式。如果你對我們為什麼使用 Pony 來編寫 Wallaroo 甚感興趣,我們有一篇關於它的 博文。
你可以把 Pony 想象成某種“Rust 遇上 Erlang”的東西。Pony 有著最引人注目的特性,它們是:
此外,它可以被編譯為高效的原生代碼,它是在開放的情況下開發的,在兩句版 BSD 許可證下發布。
以上說的功能不少,但在這裡我將重點關注那些對我們公司來說採用 Pony 至關重要的功能。
使用大多數我們現有的工具編寫快速、安全、高效、高並行的程式並非易事。“快速、高效、高並行”是可實現的目標,但加入“安全”之後,就困難了許多。對於 Wallaroo,我們希望同時實現四個目標,而 Pony 讓實現它們更加簡單。
Pony 讓併行變得簡單。部分是通過提供一個固執的並行方式實現的。在 Pony 語言中,所有的並行都是通過 Actor 模型 進行的。
Actor 模型以在 Erlang 和 Akka 中的實現最為著名。Actor 模型出現於上世紀 70 年代,細節因實現方式而異。不變的是,所有計算都由通過非同步訊息進行通訊的 actor 來執行。
你可以用這種方式來看待 Actor 模型:物件導向中的物件是狀態 + 同步方法,而 actor 是狀態 + 非同步方法。
當一個 actor 收到一個訊息時,它執行相應的方法。該方法可以在只有該 actor 可存取的狀態下執行。Actor 模型允許我們以並行安全的方式使用可變狀態。每個 actor 都是單執行緒的。一個 actor 中的兩個方法絕不會並行執行。這意味著,在給定的 actor 中,資料更新不會引起資料競爭或通常與執行緒和可變狀態相關的其他問題。
Pony actor 通過一個高效的工作竊取排程程式來排程。每個可用的 CPU 都有一個單獨 Pony 排程程式。這種每個核心一個執行緒的並行模型是 Pony 嘗試與 CPU 協同工作以盡可能高效執行的一部分。Pony 執行時嘗試盡可能利用 CPU 快取。程式碼越少干擾快取,執行得越好。Pony 意在幫你的程式碼與 CPU 快取友好相處。
Pony 的執行時還會有每個 actor 的堆,因此在垃圾收集期間,沒有 “停止一切” 的垃圾收集步驟。這意味著你的程式總是至少能做一點工作。因此 Pony 程式最終具有非常一致的效能和可預測的延遲。
Pony 型別系統引入了一個新概念:參照能力,它使得資料安全成為型別系統的一部分。Pony 語言中每種變數的型別都包含了有關如何在 actor 之間分享資料的資訊。Pony 編譯器用這些資訊來確認,在編譯時,你的程式碼是無資料競爭和無死鎖的。
如果這聽起來有點像 Rust,那是因為本來就是這樣的。Pony 的參照功能和 Rust 的借用檢查器都提供資料安全性;它們只是以不同的方式來接近這個目標,並有不同的權衡。
決定是否要在一個非業餘愛好的專案上使用一門新的程式語言是困難的。與其他方法想比,你必須權衡工具的適當性和不成熟度。那麼,Pony 和你搭不搭呢?
如果你有一個困難的並行問題需要解決,那麼 Pony 可能是一個好選擇。解決並行應用問題是 Pony 之所以存在的理由。如果你能用一個單執行緒的 Python 指令碼就完成所需操作,那你大概不需要它。如果你有一個困難的並行問題,你應該考慮 Pony 及其強大的無資料競爭、並行感知型別系統。
你將獲得一個這樣的編譯器,它將阻止你引入許多與並行相關的錯誤,並在執行時為你提供出色的效能特徵。
如果你準備好開始使用 Pony,你需要先在 Pony 的網站上存取 學習部分。在這裡你會找到安裝 Pony 編譯器的步驟和學習這門語言的資源。
如果你願意為你正在使用的這個語言做出貢獻,我們會在 GitHub 上為你提供一些 初學者友好的問題。
同時,我迫不及待地想在 我們的 IRC 頻道 和 Pony 郵寄清單 上與你交談。
要了解更多有關 Pony 的訊息,請參閱 Sean Allen 2018 年 7 月 16 日至 19 日在俄勒岡州波特蘭舉行的 第 20 屆 OSCON 會議 上的演講: Pony,我如何學會停止擔心並擁抱未經證實的技術。