大家好,我是了不起。
最近我們在專案中,透過使用 protobuf 格式作為儲存資料的一個載體。一個不小心就給自己埋了個大坑,還是過了好久才發現。
protobuf 簡介
protobuf 全名為Protocal buffers. 它是由Google 研發的,一種可跨語言、可跨平台、可擴展的序列化數據的機制。類似於 XML ,但它更小、更快、更簡單。你只需要定義一次你希望的資料如何被結構化,然後你可以使用它的產生工具,產生包含一些序列化和反序列化等操作的原始碼。可以輕鬆地從各種資料流和使用各種程式語言寫入和讀取結構化的資料。
proto2版本支援在Java、Python、Objective-C和C 中產生程式碼。使用新的proto3語言版本,你還可以使用Kotlin、Dart、Go、Ruby、PHP和C#,還有更多的語言。
怎麼發現的?
在我們的新專案中,我們透過使用 protobuf 格式來儲存專案運行的資料。這樣我們在調試過程中,可能會根據現場錄製的資料進行本地的調試。
message ImageData { // ms int64 timestamp = 1; int32 id = 2; Data mat = 3; } message PointCloud { // ms int64 timestamp = 1; int32 id = 2; PointData pointcloud = 3; } message State { // ms int64 timestamp = 1; string direction = 2; } message Sensor { repeated PointCloud point_data = 1; repeated ImageData image_data = 2; repeated State vehicle_data = 3; }
我們定義了這樣一組數據, 然後儲存的時候,因為Sensor 這3個資料來源的幀率不一樣,因此儲存的時候,單一Sensor 中其實只包含了一組數據,另外兩個類型的資料並沒有包含進去。
當我們只錄製單一 pack 的時候,我們並沒有遇到問題。直到我們覺得單一包,不能長時間錄製,我們需要找一種解決方法來分割包 。
當時覺得這個一定是很簡單的,我們就設定了一個套件達到 500M 的時候,我們就讓後面的資料存到新的套件裡。很順利的寫完,然後放到現場進行資料錄製。錄製一段時間之後,我們把包包拿回來進行模擬測試我們的新程式。發現有些包的資料解析出來是有問題的。程式運行到一半會卡在那裡不動。經過多次測試,發現部分包有這個問題。
我們一開始懷疑的是,判斷檔案大小的方式不對,影響到了分包。因為判斷文件大小的時候,會去開啟文件。但是經過好幾種其他的不打開文件的方式判斷,從而進行分割。還是遇到了部分錄製的包有問題。
這時我才懷疑到 protobuf 對儲存資料會有一些特殊的要求。後來我看了一些文章,了解到 protobuf 儲存多組資料到一個檔案需要有標誌符。要不然後面從檔案解析回來的時候,protobuf 因為不知道單一資料的停止符在哪裡,導致資料解析出錯。
到這裡,這個坑出現了。 我們儲存了一系列的資料到單一套件中,沒有做任何分隔符號的操作。 protobuf在解析的時候,把文件中所有的內容都解析成了單一Sensor。 Sensor 中包含裡所有數據, protobuf 主動合併了所有儲存的資料。
在這時,我才發現以前單包錄製的時候,數據都是對的,那真的是我運氣好。 protobuf恰好解析成功了。
要怎麼解決呢?
既然知道 protobuf 會這麼操作,那我們就只要知道 protobuf 怎麼分割就行了。這個方法還真不好找,因為像我們這樣使用的人太少了。中文搜尋完全搜不到這一塊的內容,可能大家都不會使用protobuf來儲存資料吧,大家使用的方式應該都是多個服務中進行互動的場景吧。
最後透過stackoverflow上的一些回答找到了答案,從回答中得知,這個解決辦法在 protobuf 3.3 的時候,才正式被合併進去。看起來這個功能真的很少用。
bool SerializeDelimitedToOstream(const MessageLite& message, std::ostream* output); bool ParseDelimitedFromZeroCopyStream( MessageLite* message, io::ZeroCopyInputStream* input, bool* clean_eof);
透過這對方法,可以對檔案進行依照資料流一個一個的儲存讀取。再也不用擔心資料被合併讀取。
當然透過這種方式儲存的數據,不能被原來的解析方式所解析,儲存的而進行格式完全變了。這種方式會先儲存二進位資料的大小,再儲存二進位資料。
結束語
經過一番折騰,終於搞定了這個分割的坑。使用場景可能比較小眾,導致了許多資料根本找不到。靠自己看原始碼才發現這些問題。 C 的原始碼真不好讀,有很多的模板方法、模板類別容易錯過一些細節。最後還是看的C#的程式碼,才完全確認的。
以上是原話重寫:一個意外的發現是,原本被視為 bug 的問題其實是 Protobuf 設計中的一個特性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python更易學且易用,C 則更強大但複雜。 1.Python語法簡潔,適合初學者,動態類型和自動內存管理使其易用,但可能導致運行時錯誤。 2.C 提供低級控制和高級特性,適合高性能應用,但學習門檻高,需手動管理內存和類型安全。

Python和C 在内存管理和控制方面的差异显著。1.Python使用自动内存管理,基于引用计数和垃圾回收,简化了程序员的工作。2.C 则要求手动管理内存,提供更多控制权但增加了复杂性和出错风险。选择哪种语言应基于项目需求和团队技术栈。

Python在科學計算中的應用包括數據分析、機器學習、數值模擬和可視化。 1.Numpy提供高效的多維數組和數學函數。 2.SciPy擴展Numpy功能,提供優化和線性代數工具。 3.Pandas用於數據處理和分析。 4.Matplotlib用於生成各種圖表和可視化結果。

選擇Python還是C 取決於項目需求:1)Python適合快速開發、數據科學和腳本編寫,因其簡潔語法和豐富庫;2)C 適用於需要高性能和底層控制的場景,如係統編程和遊戲開發,因其編譯型和手動內存管理。

Python在數據科學和機器學習中的應用廣泛,主要依賴於其簡潔性和強大的庫生態系統。 1)Pandas用於數據處理和分析,2)Numpy提供高效的數值計算,3)Scikit-learn用於機器學習模型構建和優化,這些庫讓Python成為數據科學和機器學習的理想工具。

每天學習Python兩個小時是否足夠?這取決於你的目標和學習方法。 1)制定清晰的學習計劃,2)選擇合適的學習資源和方法,3)動手實踐和復習鞏固,可以在這段時間內逐步掌握Python的基本知識和高級功能。

Python在Web開發中的關鍵應用包括使用Django和Flask框架、API開發、數據分析與可視化、機器學習與AI、以及性能優化。 1.Django和Flask框架:Django適合快速開發複雜應用,Flask適用於小型或高度自定義項目。 2.API開發:使用Flask或DjangoRESTFramework構建RESTfulAPI。 3.數據分析與可視化:利用Python處理數據並通過Web界面展示。 4.機器學習與AI:Python用於構建智能Web應用。 5.性能優化:通過異步編程、緩存和代碼優

Python在開發效率上優於C ,但C 在執行性能上更高。 1.Python的簡潔語法和豐富庫提高開發效率。 2.C 的編譯型特性和硬件控制提升執行性能。選擇時需根據項目需求權衡開發速度與執行效率。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

禪工作室 13.0.1
強大的PHP整合開發環境

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具