本文主要是为进程间通信(特别是语言都不同的进程)提供一种新的思路本想法来源于RoboMaster比赛中的神符检测,神符是指一个9宫格的手写体数字(Mnist)或火焰体动态数字,需要用到机器学习或深度学习模型对数字进行识别,从检测大符到识别全部数字到发射子弹,整个过程不能超过1.5秒,全部的运算量都集中在搭载在机器小车上的miniPC,由于miniPC性能有限,且除了这个程序之外还有个非常占用资源的自动射击程序,所以整个程序使用的是C++的代码。一开始我们使用的是xgboost,在python上把模型训练完成之后,把预测代码再改写成C++。而后来发现xgboost在真实场景上的准确率较低(只有70%),于是改为了复杂的深度学习模型,准确率上几乎可以达到100%。但此时的python代码已经比较复杂,再全部改成C++已经不现实,所以开始寻找一种能实现两者间通信的方案。

网上已有的通信方案C++ 与python的混合编程方案比较多,比如使用,说实话,我没认真看,需要的自己去百度或谷歌吧

进程间通信的常见的方案有共享内存、消息队列、管道等等,但是实现难度较大,特别是对于不同语言的程序

基于Redis的通信方案

基本思路Redis是一种基于内存的NoSQL 数据库,所以读写速度非常快,且使用非常简单。但其底层是基于socket通信,所以速度比共享内存、消息队列要慢一个级别,但在本场景中,能有效解决问题

在本应用场景中,每次需要通信的数据是9张图片,每张图片是28×28像素,所以其实就是 9 x 28 x 28的矩阵

所以,在C++程序中进行检测和提取图像,将9张图片的像素值依次读取进来,存储进Redis,通过标志位的方式告诉python程序进行读取,完成预测之后再将结果存储进redis,并让C++程序进行调用。整个程序的活动图如下:


理论上,因为都是基于内存的,所以这种方法的速度只会稍慢于C++的引用,相当于进行了一次深拷贝。

得益于redis的高效读取,在没有gpu的速下,在mac i7 16G的配置上跑完一次读取和预测大概需要0.3秒,即使在性能较差的miniPC上,一次耗时大概在0.6秒,主要时间消耗都在预测上,如下图:


代码实现C++ 使用hiredis

mac上安装方法:brew install hiredis

ubuntu安装方法:apt-get install hiredisCMake(仅供考):

cmake_minimum_required(VERSION 3.6)
project(rune)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
find_package(OpenCV REQUIRED)
add_executable(rune ${SOURCE_FILES})
link_directories(/usr/local/Cellar/hiredis/0.13.3/lib)
target_link_libraries(rune libhiredis.dylib libhiredis.0.13.dylib libhiredis.a)
TARGET_LINK_LIBRARIES(rune ${OpenCV_LIBS})demo1: 连接数据库
redisContext* connect_redis(){
redisContext *context = redisConnect("127.0.0.1", 6379);
if(context->err) {
redisFree(context);
printf("connect redisServer err:%s\n", context->errstr);
return NULL;
}
printf("connect redisServer success\n");
return context;
}demo2: 测试redis lrange 操作
void test_redis_lrange(redisContext *context){
redisReply *result = (redisReply *)redisCommand(context, "lrange IMAGE_NAME_LIST 0 -1");
redisReply **elements = result->element;
size_t size = result->elements;
for(int i=0; i < size; i++){
string re = elements[i]->str;
int r = re.at(7) - 48;
cout << "r:" << r<<endl;
}
freeReplyObject(result);
cout << endl;
}

一点经验:由于关于hiredis的文档比较少,所以很多数、返回值不得不自己进行测试,通过阅读源代码是一种方式,我比较喜欢的是通过jetbrain CLion的debug模式进行查看。如下图,在不清楚hiredis的lrange返回的参数的情况下,我通过在返回值那里设断点,通过添监视等操作来判断如何正确获取返回值。并且,Clion是可以跨平台的,对学生免费。

Python 使用redis这个比较简单,在这里仅提供一个demo,这个demo是我自己写某个比较大的爬虫项目时对redis进行封装的一系列接口。