簡體   English   中英

Clojure / Java的高效二進制序列化

[英]Efficient binary serialization for Clojure/Java

我正在尋找一種方法來有效地將Clojure對象序列化為二進制格式 - 即不僅僅是做經典的打印和讀取文本序列化。

即我想做的事情:

(def orig-data {:name "Data Object" 
                :data (get-big-java-array) 
                :other (get-clojure-data-stuff)})

(def binary (serialize orig-data))

;; here "binary" is a raw binary form, e.g. a Java byte array
;; so it can be persisted in key/value store or sent over network etc.

;; now check it works!

(def new-data (deserialize binary))

(= new-data orig-data)
=> true

我的動機是我有一些包含大量二進制數據的大型數據結構(在Java數組中),我想避免將這些全部轉換為文本並重新轉換回來的開銷。 此外,我正在嘗試保持格式緊湊,以最大限度地減少網絡帶寬使用。

我想要的具體功能:

  • 輕量級,純Java實現
  • 支持Clojure的所有標准數據結構以及所有Java基元,數組等。
  • 不需要額外的構建步驟/配置文件 - 我寧願它只是“開箱即用”工作
  • 在所需的處理時間方面表現良好
  • 二進制編碼表示的緊湊性

在Clojure中執行此操作的最佳/標准方法是什么?

我可能在這里遺漏了一些東西,但標准Java序列化有什么問題? 太慢,太大,別的什么?

用於普通Java序列化的Clojure包裝器可能是這樣的:

(defn serializable? [v]
  (instance? java.io.Serializable v))

(defn serialize 
  "Serializes value, returns a byte array"
  [v]
  (let [buff (java.io.ByteArrayOutputStream. 1024)]
    (with-open [dos (java.io.ObjectOutputStream. buff)]
      (.writeObject dos v))
    (.toByteArray buff)))

(defn deserialize 
  "Accepts a byte array, returns deserialized value"
  [bytes]
  (with-open [dis (java.io.ObjectInputStream.
                   (java.io.ByteArrayInputStream. bytes))]
    (.readObject dis)))

 user> (= (range 10) (deserialize (serialize (range 10))))
 true

有些值無法序列化,例如Java流和Clojure atom / agent / future,但它應該適用於大多數普通值,包括Java原語和數組以及Clojure函數,集合和記錄。

你是否真的保存了什么取決於。 在我對小型數據集的有限測試中,序列化為文本和二進制似乎是大致相同的時間和空間。

但是對於大部分數據是Java基元數組的特殊情況,Java序列化可以快幾個數量級並節省大量空間。 (在筆記本電腦上快速測試,100k隨機字節:序列化0.9毫秒,100kB;文本490毫秒,700kB。)

請注意, (= new-data orig-data)測試對數組不起作用(它委托給Java的equals ,對於數組只測試它是否是同一個對象),所以你可能想要/需要編寫自己的相等函數測試序列化。

user> (def a (range 10))
user> (= a (range 10))
true
user> (= (into-array a) (into-array a))
false
user> (.equals (into-array a) (into-array a))
false
user> (java.util.Arrays/equals (into-array a) (into-array a))
true

Nippy是imho的最佳選擇之一: https//github.com/ptaoussanis/nippy

你考慮過Google的protobuf嗎? 您可能希望使用Clojure的接口檢查GitHub存儲庫

如果您沒有提前架構,則序列化為文本可能是您最好的選擇。 要序列一般任意數據,你需要做大量的工作來保存對象圖,並做反思,看看如何序列一切......至少Clojure的打印機可以做一個靜態的,沒有反射查找print-method每個項目的print-method

相反,如果您真的需要優化的有線格式,則需要定義架構。 我曾經使用過來自java的thrift和來自clojure的protobuf:既不是很有趣,但如果你提前計划的話,這並不是很麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM