🎃
mmapによるプロセス間通信 (C++, C#, Python)
こんな人へ
- プロセス間,異言語でもリアルタイムなデータ連携したい。
- ソケット通信の速度では不満。
- Pythonを深層学習専用のサービスにして,それ以外はC++やC#で捌きたい。
- ROSのPub/Subで画像や点群が重たいと感じる。
どうぞ
利用例(Python -> C++, C#)
- Python
import time
import numpy as np
import cv2
from shared_memory_pool import *
if __name__ == "__main__":
cap = cv2.VideoCapture(os.path.join(os.path.dirname(__file__), "sample.mp4"))
delay = 1 / cap.get(cv2.CAP_PROP_FPS)
path = os.path.join(os.path.dirname(__file__), "shared.pool")
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
buf_capacity = w * h * 3
with SharedMemoryPool(path, buf_capacity, 2) as memory:
memory.flush()
while True:
time.sleep(delay)
ret, frame = cap.read()
if ret:
buf = frame.tobytes()
while memory.try_write(buf) == False: pass
print(f"Wrote {len(buf)} bytes.")
else:
break
- C++
#include "shared_memory_pool.h"
#include <vector>
int main(void)
{
const int buf_capacity = 1920 * 1080 * 3;
std::vector<unsigned char> buf(buf_capacity);
SharedMemoryPool memory("../py/shared.pool", buf_capacity, 2);
memory.flush();
int buf_size = 0;
while (true)
{
if (memory.try_read(buf.data(), buf_size))
{
std::cout << "Received: " << buf_size << " bytes." << std::endl;
}
else sleep_msec(10);
}
return 0;
}
- C#
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../../py/shared.pool");
var bufCapacity = 1920 * 1080 * 3;
using var memory = new SharedMemoryPool(path, bufCapacity, 2);
memory.Flush();
while (true)
{
if (memory.TryRead(out var buf))
{
Console.WriteLine($"Received: {buf.Length} bytes.");
}
else Thread.Sleep(10);
}
解説
だいたいREADMEに書いてますが,補足です。
- 通信したい2つのプロセスで,同じファイルパスとプールサイズ,1データの最大バイト数を指定してやると動きます。ファイルは無ければ新規作成,すでにあればデータサイズのみ再確保する形で初期化されます。
- ファイルには前回実行時のデータが残っていることがあるので,キャッシュクリア用にflush関数を用意しています。最初に立ち上げるプロセスに入れることを推奨します。
- お手製のmutexが働いています。読み書きのタイミングが重なったときはtry_read,try_writeがfalseを返してくるようにしていますので,完了するまで待つか諦めるかは自分で実装して決めてください。
- 各クラスは依存ライブラリ無しなのでコピペしてもらえれば動きます。
- エンコード/デコードをしない方が速いです。生データを送りましょう。
- mmapの実体はディスク上のファイルなので,頻繁に読み書きして大丈夫なのかは知りません。
Discussion