一次失敗的緩存試驗和對Java序列化的認(rèn)知

背景

仍然是樹重建實驗,從點云里構(gòu)建鄰接圖是一個時間開銷比較大的步驟,對于幾千個數(shù)據(jù)點而言,一個O(N^2)的建圖過程大概會花幾秒左右,建圖屬于下圖中的 Initial Skeleton 步驟,然而我每次改動的代碼都在 Refinement 步驟里,也就是說,每次我點擊 Run 按鈕時,都要重復(fù)生成一模一樣的鄰居圖

時間開銷表

如果把生成的中間數(shù)據(jù)都緩存起來,重新Run 時直接讀取緩存,這樣就可以節(jié)省掉等待的時間了。

一開始的做法

我寫了一個接口,用來表示緩存數(shù)據(jù)的容器。

import java.io.Serializable;

/**
 * T 類型的數(shù)據(jù)用于緩存!
 * @param <T>
 */
public interface CachedData<T extends Serializable> {

    T getData();

    void setData(T s);

    Class<T> getContentType();

    boolean checkData();
}

我在實驗代碼使用 Spring IOC 容器來管理 Java Bean,每個實現(xiàn)了CachedData 接口的類會被我標(biāo)注為組件(@Component),寫 getData(),setData() 方法是為了在序列化和反序列化中讀取和注入數(shù)據(jù)。

聲明 getContentType() 是為了處理 Java 假泛型的問題,因為我需要在反序列化之后做類型檢查,不能因為緩存讀取錯誤就讓程序掛掉,但是這里的類型是T,泛型類型只能在編譯時獲取,無法在運行時獲取,我就寫這么一個方法在具體實現(xiàn)類里面給出 T 的類型信息。

讀 cache 的做法如下:

CachedData data = xxxx;
FileInputStream stream = new FileInputStream("xxxx.cache");
ObjectInputStream objStream = new ObjectInputStream(stream);
Serializable obj = (Serializable) objStream.readObject();
if (data.getContentType().isInstance(obj) {
    data.setData(obj);
}

然后我就很歡喜地拿圖1里面的第二條數(shù)據(jù)進行測試,結(jié)果讓我大跌眼鏡,直接從 cache 文件里讀鄰接圖居然比在內(nèi)存里計算要慢

后來就查了一下Java序列化相關(guān)的 東西, Java 序列化雖然會把二進制數(shù)據(jù)寫入文件,但是除了字段的值外,還會寫入其他的信息比如類信息(class),如果class引用了其他的class,就會存下這些數(shù)據(jù)。實際上Java的序列化和反序列化本身并不是很高效的操作。

如果使用JSON進行序列化呢?有空我要嘗試一下,據(jù)說比Serializable還要快一些。

其他的嘗試(20180515)

搜索了一下 Java 的高效序列化庫,看到了 kryo,Github上最新的版本是 4.0.2。這里把 Kryo 4.0.2,GSON 2.8.0,Oracle Java 8 Serializable 三者進行了對比,用比較學(xué)術(shù)的三線表展示一下對比結(jié)果:

幾種序列化結(jié)果的對比

第一列,操作說明:

  • Load Data 是我的實驗代碼中從類 ply 格式的點云文件中讀取三維數(shù)據(jù)點操作。輸出 List<Point3d> 格式的數(shù)據(jù)。
  • Build Octree 是求出點云的Bounding Box,然后對包圍盒遞歸劃分八叉樹,最后求出所有八叉樹格子。輸出 List<List<Point3d>> 格式的數(shù)據(jù)。
  • Build 5-NN Graph,對數(shù)據(jù)點求5近鄰圖。輸出 HashMap<Long, HashMap<Long, Double> > 格式的數(shù)據(jù)。
  • Extract Skeleton,求最短路徑圖,按測地距離決定結(jié)點先后順序,連接成初始骨架。輸出數(shù)據(jù)比較復(fù)雜。

這 4 個步驟都會輸出一些數(shù)據(jù),這個表就是對比 3 種序列化方法對輸出數(shù)據(jù)的反序列化性能。幾個步驟的數(shù)據(jù)大小不好衡量,我放出了 JSON 格式的數(shù)據(jù)大小(第六列)。

最后粗暴的對比結(jié)果就是:

Kryo 4.0.2 > GSON 2.8.0 > Oracle Java 8 Serializable

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容