摘要:本文將介紹如何進行序列化性能檢測的重要性以及在分布式系統中的應用。另一個鮮有人知的特點就是可被序列化。所以當的使用造成性能問題時,就要使用備選方案。下面就是當在中序列化時,非采集的的情況。
本文將介紹如何進行 Java Lambdas 序列化性能檢測、Lambdas 的重要性以及 Lambdas 在分布式系統中的應用。
Lambdas 表達式是 Java 8 中萬眾期待的新特性,其若干用途包括:
為匿名內部類減少所需樣本代碼。
縮小值的作用域。Lambdas 表達式中的 this 不會涉及到外部類,減少了內存泄露。
輕松集成現有 API 與新的 Streams API。
Lambdas 另一個鮮有人知的特點就是可被序列化。
為什么對 Lambda 序列化?序列化有益于對象的狀態持久化和網絡傳輸。 Lambdas 應該盡可能無狀態,這樣就可以保存 Lambdas ,但這并不是典型的用例。
Lambdas 表達式的目的是給程序庫傳遞代碼片段,使之與庫中正在運行的程序交互。但是如果程序庫支持像 Chronicle Engine 這樣的分布式系統,那又會怎么樣?
什么是 Chronicle Engine?Chronicle Engine 是一個庫,可讓用戶使用各自的應用程序遠程訪問數據結構,無論是用 Java、C# 客戶端,還是用 NFS 文件系統。該庫還支持存儲和持久化數據,也支持復制。
分布式系統中的 Lambdas對于某些局部運行的操作,使用 Lambdas 執行不失為一種簡單可行的方法。示例操作如下:
MapViewmap = acquireMap(“map-name”, String.class, Long.class); map.put(“key”, 1); long ret = map.applyToKey(“key”, v -> v + 1); // ret == 2
這里沒有必要知道數據的具體存儲位置,如果是遠程服務器,就會在那臺服務器上對 Lambda 序列化,然后執行,并將結果返回。
上圖顯示了 OneAPM 如何監控和讓 Java 應用之間的調用關系可視化。
Capturing Lambda不獲取字段的 Lambda 可以被 Java 更高效地處理,因為每個實例都一樣,所以并不需要每次都創建新的對象。但是,若編譯時 Lambda 獲取到未知值,就需要創建新的對象,并將獲取的值保存。
Non capturing Lambda
FunctionappendStar = s -> s + "*"
Capturing Lambda
String star = "*"; Function可序列化的 LambdasappendStar = s -> s + star;
Lambdas 默認是不可序列化的,必須實現一種可序列化的接口。可以使用強制轉換把接口類型轉換為所需類型的一種方式。
FunctionappendStar = (Function & Serializable) (s -> s + star);
筆者個人不喜歡這樣做,因為這樣會破壞減少代碼的目標。一個解決的方法就是定義自己所需的可序列化的接口。
@FunctionalInterface public interface SerializableFunction extends Function, Serializable {
這就需要如下所寫:
SerializableFunctionappendStar = s -> s + star;
或者按照這種方法寫入:
R applyToKey(K key, @NotNull SerializableFunction function) {
該庫的調用者就可以如下所寫,而不需要任何樣本代碼。
String s = map.applyToKey(“key”, s-> s + “*”);Lambdas 的實時查詢
利用序列化的 Lambdas,可進行如下所示的實時查詢:
// print the last name of all the people in NYC acquireMap(“people”, String.class, Person.class).query() .filter(p -> p.getCity().equals(“NYC”)) // executed on the server .map(p → p.getLastName()) // executed on the server .subscribe(System.out::println); // executed on the client.
可查詢接口是必需的,因此過濾器 Predicate 和 map 函數也必須隱式可序列化。如果需要使用 Streams API,那就要使用早期較為復雜的數據類型轉換函數 cast。
序列化 Lambdas 的性能筆者曾經在一個字符串中寫入符號“*”,并使用 JMH 對簡單的序列化的和反序列化的 Lambda 進行時延采樣,然后比較采集和非采集兩種情況下的時延,發送枚舉時兩種情況下的時延也一并比較。代碼和結果如下表所示:
99.99%的時延意味著該試驗的99.99%都是在時延之中。時間都用微秒計算。
Test | Typical latency | 99.99% latency |
---|---|---|
Java Serialization, non-capturing | 33.9 μs | 215 μs |
Java Serialization, capturing | 36.3 μs | 704 μs |
Java Serialization, with an enum | 7.9 μs | 134 μs |
Chronicle Wire (Text), non-capturing | 20.4 μs | 147 μs |
Chronicle Wire (Text), capturing | 22.5 μs | 148 μs |
Chronicle Wire (Text), with an enum | 1.2 μs | 5.9 μs |
Chronicle Wire (Binary), non-capturing | 11.7 μs | 103 μs |
Chronicle Wire (Binary), capturing | 12.7 μs | 135 μs |
Chronicle Wire (Binary), with an enum | 1.0 μs | 1.2 μs |
使用 Lambda 是很簡單,但它效率不高時,就需要找一個備選方案。所以當 Lambda 的使用造成性能問題時,就要使用備選方案。
enum Functions implements SerializableFunction{ APPEND_STAR { @Override public String apply(String s) { return s + "*"; } } }
為考察使用枚舉所起到的作用,可以比較發送到服務器的數據量的多少,在那里可以看到所有序列化的數據。
下面就是當在 TextWire 中序列化時,非采集的 Lambda 的情況。(基于 YAML)
!SerializedLambda { cc: !type lambda.LambdaSerialization, fic: net/openhft/chronicle/core/util/SerializableFunction, fimn: apply, fims: (Ljava/lang/Object;)Ljava/lang/Object;, imk: 6, ic: lambda/LambdaSerialization, imn: lambda$textWireSerialization$ea1ad110$1, ims: (Ljava/lang/String;)Ljava/lang/String;, imt: (Ljava/lang/String;)Ljava/lang/String;, ca: [ ] }
枚舉序列化如下所示:
!Functions APPEND_STAR
注意:當需要采集某些值時,不可以使用枚舉。我們要做的就是讓你通過傳遞有附加參數的枚舉,以獲得最有效的組合。
使用枚舉就像存儲過程用枚舉代替 Lambdas 的一個好處就是,可以跟蹤所有功能客戶執行和整合的方式。某些函數使用廣泛,運用枚舉使得修復任一多帶帶函數中產生的bug更為容易,因此會被經常使用。舉一個簡單的例子,MapFunction 起初有很多不同的 Lambdas,而現在已經被歸為一類。
結論如果所使用的 API 支持,可將 Lambdas 用于分布式應用程序。如果需要附加的性能,也可以使用枚舉。
原文地址:https://dzone.com/articles/measuring-the-serialization-performance-of-lambdas
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65313.html
摘要:這減輕了手動重復執行相同基準測試的痛苦,并簡化了獲取結果的流程。處理項目的代碼并從標有注釋的方法處生成基準測試程序。用和運行該基準測試得到以下結果。同時,和的基線測試結果也有略微的不同。 Java 8 已經發布一段時間了,許多開發者已經開始使用 Java 8。本文也將討論最新發布在 JDK 中的并發功能更新。事實上,JDK 中已經有多處java.util.concurrent 改動,但...
摘要:背景許多時候需要對比不同的框架或工具或算法,選擇使用性能更優的那一個。通常的做法是但這樣的做法非常不嚴謹,因為當獨立頻繁運行這一小塊代碼時,可能會針對性的做一些優化工作,而在實際的生產環境中是不會有此優化的。 背景 許多時候需要對比不同的框架或工具或算法, 選擇使用性能更優的那一個。通常的做法是 long start = System.currentTimeMillis(); for(...
摘要:分析性能的影響但是需要注意時間單位,只是微秒而已,毫秒的千分之一秒的百萬分之一。在這種情況下,優化毫秒的性能隱患無異于撿了芝麻丟了西瓜。 同步自:https://sulin.me/2019/T2ZXZB.... 在分布式系統開發中,我們經常需要將各種各樣的狀態碼、錯誤信息傳遞給最外層的調用方,這個調用方通常是http/api接口,錯誤信息比如登錄失效、參數錯誤等等。 最外層接口暴露的...
摘要:摘要添加了表達式閉包和特性支持,包括方法的引用,增強類型推斷,和虛擬擴展方法。圍繞的語言功能支持包括虛擬擴展方法,這將使接口的源代碼和二進制兼容的方式演變升級。 Author:Joseph D. Darcy Organization:Oracle Owner:Brian Goetz Created:2011/11/1 Updated:2013/2/21 Type:Feature Sta...
閱讀 4293·2021-09-24 09:47
閱讀 1184·2021-09-03 10:33
閱讀 2063·2019-08-30 11:13
閱讀 1029·2019-08-30 10:49
閱讀 1753·2019-08-29 16:13
閱讀 2046·2019-08-29 11:28
閱讀 3089·2019-08-26 13:31
閱讀 3631·2019-08-23 17:14