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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何使用字节序列化双精度数组(二进制增量编码,用于低差单调浮点数据集)...

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何使用字节序列化双精度数组(二进制增量编码,用于低差单调浮点数据集)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

低延遲系統需要高性能的消息處理和傳遞。 由于在大多數情況下,數據必須通過有線傳輸或進行序列化才能保持持久性,因此編碼和解碼消息已成為處理管道的重要組成部分。 高性能數據編碼的最佳結果通常涉及應用程序數據細節的知識。 本文介紹的技術是一個很好的例子,說明了如何利用數據的某些方面在延遲和空間復雜度方面使編碼受益。

通常,高頻交易系統周圍傳遞的最大消息以訂單簿摘錄的形式表示某種交換狀態。 即,典型的市場數據(報價)消息包含標識工具的信息和代表訂單簿頂部的一組值。 數據集的強制性成員是以實數表示的價格/匯率信息(用于買賣雙方)。

從優化的角度來看,使該數據集非常有趣的原因是:

  • 單調的
  • 低方差
  • 非負*
  • 因此,在實踐中,我們處理的是浮點數集,這些浮點數不僅經過排序(升序出價和降價要求),而且相鄰值彼此相對“接近”。 請記住,消息處理延遲對于大多數交易系統而言至關重要,因此市場行情波動,因為關鍵實體之一需要盡可能高效地傳遞。

    讓我演示如何利用所有這些功能將數字數據編碼為非常緊湊的二進制形式。 首先,兩個預告情節說明了不同序列化方法之間的區別:

    到目前為止,我們可以看到,與基于標準ByteBuffer的序列化相比,增量編碼在編碼時間上可獲得更好的結果,但是一旦數組長度超過40,它就會比Kryo (最流行的高性能序列化庫之一)更差。不過,在這里重要的是一個典型的用例場景,對于高頻交易,市場消息恰好適合陣列長度的10-40

    當我們檢查生成的消息大小(作為數組長度的函數)時,它會變得更加有趣:

    此時,應用增量編碼的好處將變得顯而易見(藍色曲線同樣適用于字節緩沖區和Kryo??序列化)。 這里發生的是,在掌握了一些有關要處理的數據的特定知識之后,可以安全地做出一些假設,從而導致序列化占用更多的CPU資源,但是在空間方面卻效率高得多。 增量壓縮背后的想法非常簡單。 讓我們從一個整數數組開始:

    • [85103、85111、85122、85129、85142、85144、85150、85165、85177]

    如果這些是整數,則不進行任何壓縮就必須使用4 * 9 = 36字節來存儲數據。 在這組數字中,特別有趣的是它們彼此相對緊密地聚集在一起。 我們可以通過引用第一個值輕松地減少存儲數據所需的字節數,然后生成一個對應的增量數組:

    • 參考:85103,[8、19、26、39、41、47、62、74]

    哇! 現在我們可以縮小為字節數組。 讓我們再次進行計算。 我們需要4個字節作為參考值(仍為int),每個增量= 8 * 1個字節= 12個字節。

    與原始的36個字節相比,這是一個很大的改進,但仍有一些優化的余地。 與其從參考值計算增量,不如依次存儲每個前任的差異:

    • 參考:85103,[8、11、7、13、2、6、15、12]

    結果是一組具有低方差和標準偏差的非單調數字。 我希望事情已經明確了。 盡管如此,還是值得詳細說明。

    至此,我們基本上得出的是一個非常適合二進制編碼的集合。 對于我們的示例,這僅意味著可以在單個字節中容納2個增量。 我們只需要一個半字節(4位)即可容納0-15范圍內的值,因此我們可以輕松地最終將原始數組壓縮為4(供參考)+ 8 * 1/2 = 8個字節。

    由于價格是用十進制數表示的,因此應用帶有二進制編碼的增量壓縮將涉及建立最大支持的精度并將小數視為整數(將它們乘以10 ^精度),從而使精度為6的1.12345678成為1123456整數。 到目前為止,所有這些都是純粹的理論推測,本文開頭有一些預告片。 我想這是演示如何使用2個非常簡單的類在Java中實現這些想法的恰當時機。

    我們將從編碼方面開始:

    package eu.codearte.encoder;import java.nio.ByteBuffer;import static eu.codearte.encoder.Constants.*;public class BinaryDeltaEncoder {public static final int MAX_LENGTH_MASK = ~(1 << (LENGTH_BITS - 1));public ByteBuffer buffer;public double[] doubles;public int[] deltas;public int deltaSize, multiplier, idx;public void encode(final double[] values, final int[] temp, final int precision, final ByteBuffer buf) {if (precision >= 1 << PRECISION_BITS) throw new IllegalArgumentException();if ((values.length & MAX_LENGTH_MASK) != values.length) throw new IllegalArgumentException();doubles = values; deltas = temp; buffer = buf;multiplier = Utils.pow(10, precision);calculateDeltaVector();if (deltaSize > DELTA_SIZE_BITS) throw new IllegalArgumentException();buffer.putLong((long) precision << (LENGTH_BITS + DELTA_SIZE_BITS) | (long) deltaSize << LENGTH_BITS | values.length);buffer.putLong(roundAndPromote(values[0]));idx = 1;encodeDeltas();}private void calculateDeltaVector() {long maxDelta = 0, currentValue = roundAndPromote(doubles[0]);for (int i = 1; i < doubles.length; i++) {deltas[i] = (int) (-currentValue + (currentValue = roundAndPromote(doubles[i])));if (deltas[i] > maxDelta) maxDelta = deltas[i];}deltaSize = Long.SIZE - Long.numberOfLeadingZeros(maxDelta);}private void encodeDeltas() {if (idx >= doubles.length) return;final int remainingBits = (doubles.length - idx) * deltaSize;if (remainingBits >= Long.SIZE || deltaSize > Integer.SIZE) buffer.putLong(encodeBits(Long.SIZE));else if (remainingBits >= Integer.SIZE || deltaSize > Short.SIZE) buffer.putInt((int) encodeBits(Integer.SIZE));else if (remainingBits >= Short.SIZE || deltaSize > Byte.SIZE) buffer.putShort((short) encodeBits(Short.SIZE));else buffer.put((byte) encodeBits(Byte.SIZE));encodeDeltas();}private long encodeBits(final int typeSize) {long bits = 0L;for (int pos = typeSize - deltaSize; pos >= 0 && idx < deltas.length; pos -= deltaSize)bits |= (long) deltas[idx++] << pos;return bits;}private long roundAndPromote(final double value) {return (long) (value * multiplier + .5d);} }

    在詳細介紹之前,請先介紹幾句話。 該代碼不是完整的,成熟的解決方案。 它的唯一目的是演示提高應用程序序列化協議的某些位的難易程度。 由于它受到了微基準測試,它也不會引起gc壓力,因為即使是最快的次要gc的影響也會嚴重扭曲最終結果,從而使api變得丑陋。 該實現也是次優的,尤其是在CPU方面,但是證明微優化不是本文的目標。 話雖如此,讓我們看看它的作用(大括號中的行號)。

    編碼方法首先進行一些基本的健全性檢查{17,18},計算將十進制轉換為整數{20}所用的乘數,并計算calculateDeltaVector()。 這又有兩個影響。

  • 通過將小數轉換為整數,從前任減去,最后將結果存儲在臨時數組{33}中,計算整個集合的滾動增量
  • 作為副作用,得出表示增量{34,36}所需的最大位數
  • 然后,encode()方法存儲正確反序列化所需的一些元數據。 它以位為單位打包精度,增量大小,并以前64位{24}打包數組長度。 然后,它存儲參考值{25}并啟動二進制編碼{27}。

    編碼增量執行以下操作:

  • 檢查它是否已經處理了所有數組條目,如果已??退出則退出{40}
  • 計算要編碼的剩余位數{41}
  • 選擇最合適的類型(給定大小,以位為單位),對剩余的位進行編碼,然后將這些位寫入緩沖區{43-46}
  • 遞歸{47}
  • 可能需要詳細說明的最后一點是encodeBits()方法本身。 根據在參數中傳遞的類型大小(以位為單位),它會循環一個臨時long,其唯一目的是用作位集,并寫入代表從long值的最高有效部分到最低有效部分的連續增量的位(范圍為字號)。

    正如預期的那樣,解碼與編碼完全相反,并且主要是關于使用元數據來重建原始double數組,直至達到指定的精度:

    package eu.codearte.encoder;import java.nio.ByteBuffer;import static eu.codearte.encoder.Constants.DELTA_SIZE_BITS; import static eu.codearte.encoder.Constants.LENGTH_BITS;public class BinaryDeltaDecoder {private ByteBuffer buffer;private double[] doubles;private long current;private double divisor;private int deltaSize, length, mask;public void decode(final ByteBuffer buffer, final double[] doubles) {this.buffer = buffer; this.doubles = doubles;final long bits = this.buffer.getLong();divisor = Math.pow(10, bits >>> (LENGTH_BITS + DELTA_SIZE_BITS));deltaSize = (int) (bits >>> LENGTH_BITS) & 0x3FFFFFF;length = (int) (bits & 0xFFFFFFFF);doubles[0] = (current = this.buffer.getLong()) / divisor;mask = (1 << deltaSize) - 1;decodeDeltas(1);}private void decodeDeltas(final int idx) {if (idx == length) return;final int remainingBits = (length - idx) * deltaSize;if (remainingBits >= Long.SIZE) decodeBits(idx, buffer.getLong(), Long.SIZE);else if (remainingBits >= Integer.SIZE) decodeBits(idx, buffer.getInt(), Integer.SIZE);else if (remainingBits >= Short.SIZE) decodeBits(idx, buffer.getShort(), Short.SIZE);else decodeBits(idx, buffer.get(), Byte.SIZE);}private void decodeBits(int idx, final long bits, final int typeSize) {for (int offset = typeSize - deltaSize; offset >= 0 && idx < length; offset -= deltaSize)doubles[idx++] = (current += ((bits >>> offset) & mask)) / divisor;decodeDeltas(idx);}}

    帶有一些測試類的源代碼可以在這里找到。 請記住,即使事實證明該代碼可以正常工作,也不適合生產。 您絕對可以使它工作而無需臨時陣列,用聰明的方法代替最大陣列大小時,可以代替全陣列掃描,也可以通過采用倒數近似除法而無需進行重量級除法。 隨意選擇這些提示或進行不同的微優化,并構建自己的專有增量編碼協議。 對于對延遲敏感的交易應用程序而言,它具有很大的區別,可將液體工具的市場數據消息大小減小20-30倍。 當然,如果切換到增量壓縮二進制編碼會對您的應用程序生態系統帶來任何價值,那么您必須弄清楚自己。 隨便發表您的發現與評論!

    參考: 如何從Fast的 JCG合作伙伴 Wojciech Kudla 獲得一個帶有字節的雙精度數組的序列化(二進制delta編碼,用于低差單調浮點數據集) 。 快點。 怪胎的博客。

    翻譯自: https://www.javacodegeeks.com/2014/01/how-to-serialize-an-array-of-doubles-with-a-byte-binary-delta-encoding-for-low-varianced-monotonic-sets-of-floating-point-data.html

    總結

    以上是生活随笔為你收集整理的如何使用字节序列化双精度数组(二进制增量编码,用于低差单调浮点数据集)...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 疯狂做爰的爽文多肉小说王爷 | 中文字幕一区二区在线观看 | 三级黄色图片 | 免费在线国产精品 | 色婷婷一区二区 | 欧美三级影院 | 操啊操| 老女人丨91丨九色 | 亚洲第一页综合 | 欧美色频 | 日本三级韩国三级三级a级中文 | 青青青在线视频 | 黄色三级免费观看 | 好吊妞精品视频 | 国内偷拍久久 | 五月av| yy6080午夜| 1024香蕉视频| 日本黄色xxx| 日本一区二区免费在线 | 日本a v在线播放 | 电影《走路上学》免费 | 日本天天色 | 中文字幕无码av波多野吉衣 | 日本在线小视频 | 亚洲精品9| 狠狠婷婷 | 蜜臀av午夜精品 | 婷婷国产精品 | 黄av网| 告诉我真相俄剧在线观看 | 亚洲精品小说 | www.97色| 日本性高潮视频 | 亚洲国产精品福利 | 亚洲色图吧 | 2019狠狠干| 免费午夜影院 | 日韩一区二区精品 | 日韩欧美在线一区二区三区 | 亚洲av无码乱码国产麻豆 | 激情宗合网| 中日韩午夜理伦电影免费 | 欧美精品毛片 | 久草www| 中文字幕日韩精品亚洲一区小树林 | 精品蜜桃一区二区三区 | 欧美成人免费看 | 日本中文字幕在线看 | julia一区二区三区中文字幕 | 久久噜噜噜精品国产亚洲综合 | 久久综合成人 | 欧美国产日韩精品 | 性少妇videosexfreexxx片 | 中文字幕在线观看不卡 | youjizzxxxxx| 色狠av| 亚洲精品午夜 | 国产精品.www | 宅男噜噜噜666在线观看 | 一级做a爱片性色毛片 | 免费在线成人av | 欧美69影院 | caopor在线| 波多野结衣之双调教hd | 涩涩网站在线看 | 久久99精品国产.久久久久 | 精品日本一区二区三区在线观看 | 亚洲第六页 | 理论片在线观看视频 | 91蜜臀精品国产自偷在线 | 日日夜夜撸啊撸 | 日日艹夜夜艹 | 久操视频在线观看 | 成人做爰www看视频软件 | av色播| 免费色网址 | wwww在线观看| 第一福利在线视频 | www.youjizz.com视频| 久久亚 | 国产精品一区二区入口九绯色 | 久久精彩| 国产欧美日韩三区 | 天天想你免费观看完整版高清电影 | 国产精品视频一二三 | 污污av | 手机在线观看av | 国产一级片免费在线观看 | 色呦呦国产 | 久久欧 | 国产在线看片 | 国内激情视频 | 青青草在线观看视频 | 中文字幕在线永久 | 欧美在线视频一区二区 | 亚洲在线一区 | 不卡的一区二区 | 亚洲小说区图片区都市 |