簡體   English   中英

C++ 和 Java 之間的低延遲 IPC

[英]Low-latency IPC between C++ and Java

對於以下情況,實現 C++/Java IPC 的最佳方法是什么?

(最近有人問了類似的問題,但我的要求更具體)

  1. 我有兩個程序——一個用 C++ 編寫,另一個用 Java 編寫——它們需要相互通信。 兩者都在同一台機器上運行。

  2. 程序相互發送消息。 消息通常很短(少於幾百字節),但可能有 100KB 或更大的大小。

  3. 消息不需要被確認(即,不是像 HTTP 那樣的請求/響應 model)。 For example, the C++ program sends a message to the Java program, and the Java program may reply by sending a message to the C++ program at a later time -- and vice versa.

  4. 一個理想的解決方案將具有 a) 非常低的延遲,b) 沒有安全問題(用戶不必授權打開端口等)和 c) 將與平台無關。

我的第一個想法是使用sockets - 每個程序都將充當另一個程序的服務器。 Sockets 的開銷比 IPC 的其他 forms 的開銷更大,如果我讓系統自動分配端口號,我不知道服務器如何通知客戶端端口號。 我也考慮過命名管道,但它們在不同平台上不受支持(至少不一致)。 JNI看起來像一個選項,但它可以跨越進程邊界嗎?

有什么建議么?

謝謝!

后續問題

  1. 如果我 go 和 sockets,我是否需要打開兩個sockets 以允許如上所述的異步通信?

我建議您使用TCP sockets

根據我的經驗,TCP sockets 的實際開銷與應用程序的其他任務的工作量相比非常非常低,至少是我用來開發的那些。 我的意思是,有時即使套接字的延遲是其他 IPC 機制的延遲的兩倍,在整個工作流程中它們的影響也很小。 它為您省去了在 Java 應用程序和 C++ 應用程序之間進行 IPC 的麻煩,這最終將要求您使用特定的 ZD52387880E1EA22817A72D3759213819NIZ 庫的開銷和庫本身的開銷。

我實際測量過,在我的 Java 應用程序中,垃圾收集器的影響遠比“環回”TCP sockets 引起的延遲重要得多。

此外,TCP sockets 比傳統的 IPC 更具可擴展性(和便攜性。)? 如果將來您必須在不同的機器上運行客戶端和服務器,在“TCP 套接字”場景中,您將不得不在“傳統 IPC”場景中進行 5 分鍾的破解。 你將不得不重寫整個 IPC 的東西。

但是,您的應用程序的一般工作流程是什么?

即使不需要確認,我也建議使用 TCP(而不是 UDP)來避免未排序的交付(這會導致在重新排列您收到的內容時感到頭疼 - 您的一些消息是 100KB,而這不適合 UDP 數據包)。

在回答您的最后一個問題時,為了讓服務器通知客戶端有關端口,您可以讓服務器使用特定的“端口”命令行參數啟動客戶端,或者讓服務器在 /tmp 下保存一個小文件(或另一個臨時目錄),里面寫着端口號。

我聽說過有關ZeroMQ的好消息,特別是針對這類場景。 在某些情況下,它甚至聲稱比 TCP 更快。 簡而言之,嘗試一下肯定不會有什么壞處。

另一種方法是使用 memory 映射文件,並通過檢查編譯器設置是否為 posix 來保持它的可移植性。 POSIX 操作系統具有mmap()並且在 windows 中,您將使用CreateFileMapping()

在 boost 庫中是 C++ 的可移植實現,在 java 中,您應該能夠使用FileChannel()

該頁面很好地解釋了如何將其用於 IPC http://en.wikipedia.org/wiki/Memory-mapped_file

當您說非常低的延遲時,您需要對其進行限定。 您可以通過 Socket 環回發送消息,RTT 為 20 微秒。 如果這足夠快,我會這樣做。

如果這還不夠快,我只需將 C++ 放在 Java 應用程序中並通過 JNI 調用它。 這將為您提供大約 30 納秒的 RTT。

使用 memory 映射數據的問題在於獲得正確的互鎖。 您可能會找到適用於一個系統但可能不適用於其他系統的解決方案。

使用 JNI 將允許訪問系統中的所有可能性,而不僅僅是 Java 中直接支持的那些; 例如,如果您使用共享 memory,這將是必要的。 然而,JNI 本身相當昂貴。

延遲問題很棘手,因為我所知道的機制都沒有提供任何保證。 總而言之,最快的可能是某種形式的共享 memory,當數據存在時使用信號喚醒另一個進程。 這將需要在 Java 端使用 JNI,但如果做得正確,可能仍然會提供最低的延遲——但是,正確執行(確保沒有消息丟失)絕非易事。 基於 Unix 的平台確實支持排隊信號,並在單獨的線程中將它們作為事件處理; 我不知道 Windows。

除此之外,命名為 pipe 通常非常有效; 延遲可以與共享的 memory 一樣好,但需要更多時間來獲取數據(因為它必須通過系統復制)。 並且應該可以直接從 Java 訪問它,而無需使用 JNI。 在 Unix 下,還可以配置 sockets 以同樣快速地響應(實際上,這就是名為 pipe 的引擎蓋下的內容); 我不知道 Java 接口是否支持這些配置選項,但是,我不知道它們是否在 Windows 下可用。

另一種方法是使用嵌入式數據庫(因為您正在考慮多個 IPC,我假設這兩個應用程序都在同一台機器上)。

我以前在一個應用程序上工作,其中 c++ 應用程序從各種渠道獲取數據並將其放入數據庫(內存數據庫;TimesTen)。 為了向用戶顯示該數據,Java 應用程序將從數據庫中查詢它。

對於您的使用,我不知道您是否願意考慮 Oracle 的 Timesten,但您也可以使用 Berkeley 的嵌入式數據庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM