日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java对象序列化的本机C / C ++类似性能

發(fā)布時(shí)間:2023/12/3 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java对象序列化的本机C / C ++类似性能 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
您是否曾經(jīng)希望過(guò)像使用C ++這樣的本地語(yǔ)言將Java對(duì)象轉(zhuǎn)換成字節(jié)流一樣快的速度? 如果您使用標(biāo)準(zhǔn)的Java序列化,您可能會(huì)對(duì)性能感到失望。 Java序列化的目的是與盡可能快而緊湊地序列化對(duì)象的目的截然不同。

為什么我們需要快速緊湊的序列化? 我們的許多系統(tǒng)都是分布式的,我們需要通過(guò)在流程之間高效地傳遞狀態(tài)進(jìn)行通信。 這種狀態(tài)存在于我們的物體內(nèi)部。 我已經(jīng)介紹了許多系統(tǒng),通常大部分成本是該狀態(tài)與字節(jié)緩沖區(qū)之間的串行化。 我已經(jīng)看到用于實(shí)現(xiàn)此目的的大量協(xié)議和機(jī)制。 一方面是易于使用但效率低下的協(xié)議,例如Java 序列化 , XML和JSON 。 另一方面,二進(jìn)制協(xié)議可以非常快速和高效,但是需要更深入的理解和技能。

在本文中,我將說(shuō)明使用簡(jiǎn)單的二進(jìn)制協(xié)議時(shí)可能實(shí)現(xiàn)的性能提升,并介紹一種Java中可用的鮮為人知的技術(shù),以實(shí)現(xiàn)與C或C ++之類的本地語(yǔ)言類似的性能。

要比較的三種方法是:

  • Java序列化 :Java中有一個(gè)對(duì)象實(shí)現(xiàn)Serializable的標(biāo)準(zhǔn)方法。
  • 通過(guò)ByteBuffer進(jìn)行二進(jìn)制 :使用ByteBuffer API的簡(jiǎn)單協(xié)議,以二進(jìn)制格式寫(xiě)入對(duì)象的字段。 這是我們認(rèn)為是好的二進(jìn)制編碼方法的基準(zhǔn)。
  • 二進(jìn)制通過(guò)不安全 :介紹不安全和其允許直接內(nèi)存操作方法的集合。 在這里,我將展示如何獲得與C / C ++類似的性能。
  • 編碼

    import sun.misc.Unsafe; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.util.Arrays;public final class TestSerialisationPerf {public static final int REPETITIONS = 1 * 1000 * 1000;private static ObjectToBeSerialised ITEM =new ObjectToBeSerialised(1010L, true, 777, 99,new double[]{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0},new long[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10});public static void main(final String[] arg) throws Exception{for (final PerformanceTestCase testCase : testCases){for (int i = 0; i < 5; i++){testCase.performTest();System.out.format('%d %s\twrite=%,dns read=%,dns total=%,dns\n',i,testCase.getName(),testCase.getWriteTimeNanos(),testCase.getReadTimeNanos(),testCase.getWriteTimeNanos() + testCase.getReadTimeNanos());if (!ITEM.equals(testCase.getTestOutput())){throw new IllegalStateException('Objects do not match');}System.gc();Thread.sleep(3000);}}}private static final PerformanceTestCase[] testCases ={new PerformanceTestCase('Serialisation', REPETITIONS, ITEM){ByteArrayOutputStream baos = new ByteArrayOutputStream();public void testWrite(ObjectToBeSerialised item) throws Exception{for (int i = 0; i < REPETITIONS; i++){baos.reset();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(item);oos.close();}}public ObjectToBeSerialised testRead() throws Exception{ObjectToBeSerialised object = null;for (int i = 0; i < REPETITIONS; i++){ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);object = (ObjectToBeSerialised)ois.readObject();}return object;}},new PerformanceTestCase('ByteBuffer', REPETITIONS, ITEM){ByteBuffer byteBuffer = ByteBuffer.allocate(1024);public void testWrite(ObjectToBeSerialised item) throws Exception{for (int i = 0; i < REPETITIONS; i++){byteBuffer.clear();item.write(byteBuffer);}}public ObjectToBeSerialised testRead() throws Exception{ObjectToBeSerialised object = null;for (int i = 0; i < REPETITIONS; i++){byteBuffer.flip();object = ObjectToBeSerialised.read(byteBuffer);}return object;}},new PerformanceTestCase('UnsafeMemory', REPETITIONS, ITEM){UnsafeMemory buffer = new UnsafeMemory(new byte[1024]);public void testWrite(ObjectToBeSerialised item) throws Exception{for (int i = 0; i < REPETITIONS; i++){buffer.reset();item.write(buffer);}}public ObjectToBeSerialised testRead() throws Exception{ObjectToBeSerialised object = null;for (int i = 0; i < REPETITIONS; i++){buffer.reset();object = ObjectToBeSerialised.read(buffer);}return object;}},}; }abstract class PerformanceTestCase {private final String name;private final int repetitions;private final ObjectToBeSerialised testInput;private ObjectToBeSerialised testOutput;private long writeTimeNanos;private long readTimeNanos;public PerformanceTestCase(final String name, final int repetitions,final ObjectToBeSerialised testInput){this.name = name;this.repetitions = repetitions;this.testInput = testInput;}public String getName(){return name;}public ObjectToBeSerialised getTestOutput(){return testOutput;}public long getWriteTimeNanos(){return writeTimeNanos;}public long getReadTimeNanos(){return readTimeNanos;}public void performTest() throws Exception{final long startWriteNanos = System.nanoTime();testWrite(testInput);writeTimeNanos = (System.nanoTime() - startWriteNanos) / repetitions;final long startReadNanos = System.nanoTime();testOutput = testRead();readTimeNanos = (System.nanoTime() - startReadNanos) / repetitions;}public abstract void testWrite(ObjectToBeSerialised item) throws Exception;public abstract ObjectToBeSerialised testRead() throws Exception; }class ObjectToBeSerialised implements Serializable {private static final long serialVersionUID = 10275539472837495L;private final long sourceId;private final boolean special;private final int orderCode;private final int priority;private final double[] prices;private final long[] quantities;public ObjectToBeSerialised(final long sourceId, final boolean special,final int orderCode, final int priority,final double[] prices, final long[] quantities){this.sourceId = sourceId;this.special = special;this.orderCode = orderCode;this.priority = priority;this.prices = prices;this.quantities = quantities;}public void write(final ByteBuffer byteBuffer){byteBuffer.putLong(sourceId);byteBuffer.put((byte)(special ? 1 : 0));byteBuffer.putInt(orderCode);byteBuffer.putInt(priority);byteBuffer.putInt(prices.length);for (final double price : prices){byteBuffer.putDouble(price);}byteBuffer.putInt(quantities.length);for (final long quantity : quantities){byteBuffer.putLong(quantity);}}public static ObjectToBeSerialised read(final ByteBuffer byteBuffer){final long sourceId = byteBuffer.getLong();final boolean special = 0 != byteBuffer.get();final int orderCode = byteBuffer.getInt();final int priority = byteBuffer.getInt();final int pricesSize = byteBuffer.getInt();final double[] prices = new double[pricesSize];for (int i = 0; i < pricesSize; i++){prices[i] = byteBuffer.getDouble();}final int quantitiesSize = byteBuffer.getInt();final long[] quantities = new long[quantitiesSize];for (int i = 0; i < quantitiesSize; i++){quantities[i] = byteBuffer.getLong();}return new ObjectToBeSerialised(sourceId, special, orderCode, priority, prices, quantities);}public void write(final UnsafeMemory buffer){buffer.putLong(sourceId);buffer.putBoolean(special);buffer.putInt(orderCode);buffer.putInt(priority);buffer.putDoubleArray(prices);buffer.putLongArray(quantities);}public static ObjectToBeSerialised read(final UnsafeMemory buffer){final long sourceId = buffer.getLong();final boolean special = buffer.getBoolean();final int orderCode = buffer.getInt();final int priority = buffer.getInt();final double[] prices = buffer.getDoubleArray();final long[] quantities = buffer.getLongArray();return new ObjectToBeSerialised(sourceId, special, orderCode, priority, prices, quantities);}@Overridepublic boolean equals(final Object o){if (this == o){return true;}if (o == null || getClass() != o.getClass()){return false;}final ObjectToBeSerialised that = (ObjectToBeSerialised)o;if (orderCode != that.orderCode){return false;}if (priority != that.priority){return false;}if (sourceId != that.sourceId){return false;}if (special != that.special){return false;}if (!Arrays.equals(prices, that.prices)){return false;}if (!Arrays.equals(quantities, that.quantities)){return false;}return true;} }class UnsafeMemory {private static final Unsafe unsafe;static{try{Field field = Unsafe.class.getDeclaredField('theUnsafe');field.setAccessible(true);unsafe = (Unsafe)field.get(null);}catch (Exception e){throw new RuntimeException(e);}}private static final long byteArrayOffset = unsafe.arrayBaseOffset(byte[].class);private static final long longArrayOffset = unsafe.arrayBaseOffset(long[].class);private static final long doubleArrayOffset = unsafe.arrayBaseOffset(double[].class);private static final int SIZE_OF_BOOLEAN = 1;private static final int SIZE_OF_INT = 4;private static final int SIZE_OF_LONG = 8;private int pos = 0;private final byte[] buffer;public UnsafeMemory(final byte[] buffer){if (null == buffer){throw new NullPointerException('buffer cannot be null');}this.buffer = buffer;}public void reset(){this.pos = 0;}public void putBoolean(final boolean value){unsafe.putBoolean(buffer, byteArrayOffset + pos, value);pos += SIZE_OF_BOOLEAN;}public boolean getBoolean(){boolean value = unsafe.getBoolean(buffer, byteArrayOffset + pos);pos += SIZE_OF_BOOLEAN;return value;}public void putInt(final int value){unsafe.putInt(buffer, byteArrayOffset + pos, value);pos += SIZE_OF_INT;}public int getInt(){int value = unsafe.getInt(buffer, byteArrayOffset + pos);pos += SIZE_OF_INT;return value;}public void putLong(final long value){unsafe.putLong(buffer, byteArrayOffset + pos, value);pos += SIZE_OF_LONG;}public long getLong(){long value = unsafe.getLong(buffer, byteArrayOffset + pos);pos += SIZE_OF_LONG;return value;}public void putLongArray(final long[] values){putInt(values.length);long bytesToCopy = values.length << 3;unsafe.copyMemory(values, longArrayOffset,buffer, byteArrayOffset + pos,bytesToCopy);pos += bytesToCopy;}public long[] getLongArray(){int arraySize = getInt();long[] values = new long[arraySize];long bytesToCopy = values.length << 3;unsafe.copyMemory(buffer, byteArrayOffset + pos,values, longArrayOffset,bytesToCopy);pos += bytesToCopy;return values;}public void putDoubleArray(final double[] values){putInt(values.length);long bytesToCopy = values.length << 3;unsafe.copyMemory(values, doubleArrayOffset,buffer, byteArrayOffset + pos,bytesToCopy);pos += bytesToCopy;}public double[] getDoubleArray(){int arraySize = getInt();double[] values = new double[arraySize];long bytesToCopy = values.length << 3;unsafe.copyMemory(buffer, byteArrayOffset + pos,values, doubleArrayOffset,bytesToCopy);pos += bytesToCopy;return values;} }

    結(jié)果

    2.8GHz Nehalem - Java 1.7.0_04 ============================== 0 Serialisation write=2,517ns read=11,570ns total=14,087ns 1 Serialisation write=2,198ns read=11,122ns total=13,320ns 2 Serialisation write=2,190ns read=11,011ns total=13,201ns 3 Serialisation write=2,221ns read=10,972ns total=13,193ns 4 Serialisation write=2,187ns read=10,817ns total=13,004ns 0 ByteBuffer write=264ns read=273ns total=537ns 1 ByteBuffer write=248ns read=243ns total=491ns 2 ByteBuffer write=262ns read=243ns total=505ns 3 ByteBuffer write=300ns read=240ns total=540ns 4 ByteBuffer write=247ns read=243ns total=490ns 0 UnsafeMemory write=99ns read=84ns total=183ns 1 UnsafeMemory write=53ns read=82ns total=135ns 2 UnsafeMemory write=63ns read=66ns total=129ns 3 UnsafeMemory write=46ns read=63ns total=109ns 4 UnsafeMemory write=48ns read=58ns total=106ns2.4GHz Sandy Bridge - Java 1.7.0_04 =================================== 0 Serialisation write=1,940ns read=9,006ns total=10,946ns 1 Serialisation write=1,674ns read=8,567ns total=10,241ns 2 Serialisation write=1,666ns read=8,680ns total=10,346ns 3 Serialisation write=1,666ns read=8,623ns total=10,289ns 4 Serialisation write=1,715ns read=8,586ns total=10,301ns 0 ByteBuffer write=199ns read=198ns total=397ns 1 ByteBuffer write=176ns read=178ns total=354ns 2 ByteBuffer write=174ns read=174ns total=348ns 3 ByteBuffer write=172ns read=183ns total=355ns 4 ByteBuffer write=174ns read=180ns total=354ns 0 UnsafeMemory write=38ns read=75ns total=113ns 1 UnsafeMemory write=26ns read=52ns total=78ns 2 UnsafeMemory write=26ns read=51ns total=77ns 3 UnsafeMemory write=25ns read=51ns total=76ns 4 UnsafeMemory write=27ns read=50ns total=77ns

    分析

    使用Java序列化在我的快速2.4 GHz Sandy Bridge筆記本電腦上寫(xiě)和讀一個(gè)相對(duì)較小的對(duì)象可能需要10,000ns,而使用Unsafe時(shí),即使考慮到測(cè)試代碼本身,也可以減少到不到100ns。 為了說(shuō)明這一點(diǎn),在使用Java序列化時(shí),成本與網(wǎng)絡(luò)躍點(diǎn)相當(dāng)! 如果您的傳輸是同一系統(tǒng)上的快速IPC機(jī)制,那么這將是非常昂貴的。

    Java序列化如此昂貴的原因有很多。 例如,它為每個(gè)對(duì)象寫(xiě)出完全限定的類和字段名稱以及版本信息。 同樣, ObjectOutputStream保留所有書(shū)面對(duì)象的集合,以便在調(diào)用close()時(shí)可以將它們合并。 對(duì)于此示例對(duì)象,Java序列化需要340字節(jié),但是對(duì)于二進(jìn)制版本,我們僅需要185字節(jié)。 Java序列化格式的詳細(xì)信息可以在這里找到。 如果我沒(méi)有使用數(shù)組存儲(chǔ)大多數(shù)數(shù)據(jù),那么由于字段名的原因,使用Java序列化,序列化的對(duì)象會(huì)大很多。 以我的經(jīng)驗(yàn),諸如XML和JSON之類的基于文本的協(xié)議甚至可能比Java序列化的效率更低。 還應(yīng)注意Java序列化是RMI所采用的標(biāo)準(zhǔn)機(jī)制。

    真正的問(wèn)題是要執(zhí)行的指令數(shù)量。 Unsafe方法有很大優(yōu)勢(shì),因?yàn)樵贖otspot和許多其他JVM中,優(yōu)化器將這些操作視為內(nèi)部操作,并用匯編指令替換了調(diào)用以執(zhí)行內(nèi)存操作。 對(duì)于基本類型,這將導(dǎo)致單個(gè)x86 MOV指令,該指令通常可以在單個(gè)周期內(nèi)發(fā)生。 如我在上一篇文章中所述,可以通過(guò)讓Hotspot輸出優(yōu)化的代碼來(lái)看到詳細(xì)信息。

    現(xiàn)在必須說(shuō),“ 功能強(qiáng)大,責(zé)任重大 ”,如果您使用Unsafe,它實(shí)際上與C語(yǔ)言編程相同,并且當(dāng)偏移量錯(cuò)誤時(shí),也會(huì)發(fā)生內(nèi)存訪問(wèn)沖突。

    添加一些上下文

    “ Google協(xié)議緩沖區(qū)之類的怎么樣?”,聽(tīng)說(shuō)您大聲疾呼。 這些是非常有用的庫(kù),通常可以比Java序列化提供更好的性能和更大的靈活性。 但是,它們并不像我在此處所示的那樣接近使用Unsafe的性能。 協(xié)議緩沖區(qū)解決了一個(gè)不同的問(wèn)題,并提供了很好的自描述消息,這些消息在各種語(yǔ)言之間都可以正常工作。 請(qǐng)使用不同的協(xié)議和序列化技術(shù)進(jìn)行測(cè)試以比較結(jié)果。

    另外你之間的精明會(huì)問(wèn),“什么字節(jié)順序的整數(shù)(字節(jié)順序)寫(xiě)的?” 使用不安全時(shí),字節(jié)以本機(jī)順序?qū)懭搿?這對(duì)于IPC以及相同類型的系統(tǒng)之間非常有用。 如果系統(tǒng)使用不同的格式,則必須進(jìn)行轉(zhuǎn)換。

    我們?nèi)绾翁幚硪粋€(gè)類的多個(gè)版本或如何確定對(duì)象所屬的類? 我想讓本文重點(diǎn)關(guān)注,但讓我們說(shuō)一個(gè)簡(jiǎn)單的整數(shù)來(lái)表示實(shí)現(xiàn)類是標(biāo)題所需的全部。 該整數(shù)可用于查找反序列化操作的適當(dāng)實(shí)現(xiàn)。

    我經(jīng)常聽(tīng)到反對(duì)二進(jìn)制協(xié)議和文本協(xié)議的爭(zhēng)論,那么人類可讀和調(diào)試該怎么辦? 有一個(gè)簡(jiǎn)單的解決方案。 開(kāi)發(fā)用于讀取二進(jìn)制格式的工具!

    結(jié)論

    總之,可以通過(guò)有效使用相同的技術(shù),在Java中實(shí)現(xiàn)相同的本機(jī)C / C ++性能級(jí)別,以將對(duì)象與字節(jié)流進(jìn)行串行化。 我已為其提供了基本實(shí)現(xiàn)的UnsafeMemory類,可以輕松擴(kuò)展以封裝此行為,從而在使用這種敏銳的工具時(shí)可以保護(hù)自己免受許多潛在問(wèn)題的影響。

    現(xiàn)在是急需解決的問(wèn)題。 如果Java通過(guò)本地提供我對(duì)Unsafe所做的有效工作來(lái)為Serializable提供替代的Marshallable接口,會(huì)不會(huì)更好呢???

    參考: Mechanical Sympathy博客上的JCG合作伙伴 Martin Thompson提供的Java對(duì)象序列化的本機(jī)C / C ++類性能,用于Java對(duì)象序列化 。


    翻譯自: https://www.javacodegeeks.com/2012/07/native-cc-like-performance-for-java.html

    總結(jié)

    以上是生活随笔為你收集整理的Java对象序列化的本机C / C ++类似性能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。