Node与Python 双向通信的实现代码


Posted in Javascript onJuly 16, 2021

第三方数据供应商把数据和Python封装到一起,只能通过调用 Python方法来实现数据查询,如果可以通过Node 简单封装下实现 Python 方法调用可以快速上线并节省开发成本。

最简单粗暴的通信方式是 Nodejs调用一下 Python 脚本,然后获取子进程的输出,但是由于每次 Python 启动并加载数据包的过程比较漫长,所以对该过程优化。

进程通信

index.py

# 封装的 Python 包, 体积巨大
from mb import MB
# 从数据包中查询
mbe.get('1.0.1.0')

index.js

const { spawn } = require('child_process');
const ls = spawn('python3', ['index.py']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code $[code]`);
});

通过child_process.spawn来派生 Python 子进程,监听 stdout 输出。上述方式也是官方文档中的示例,目前该示例存在两个问题:

  • Nodejs 没有向 Python 发送数据
  • Nodejs 调用完毕后,Python 子进程会退出;下次查询需要再次调用Python命令进行加载文件,查询数据;无法实现一次内存加载,多次使用。

进程双向通信

保证一次数据加载,多次使用的前提是 Python 进程启动后不能退出。Python 进程之所以退出是因为无事可做,所以常见的手段有循环,sleep,监听端口,这些手段可以翻译成同步阻塞任务,同步非阻塞任务,其中代价最小的就是同步非阻塞任务,然后可以想到 Linux 的 select,epoll,简单搜索了下 Python 的 epoll,好像还有原生的包。

index.py - 通过 epoll 监听 stdin

import sys
import fcntl
import select
from mb import MB
import json

mbe = MB('./data')

# epoll 模型
fd = sys.stdin.fileno()
epoll = select.epoll()
epoll.register(fd, select.EPOLLIN)

try:
    while True:
        events = epoll.poll(10) # 同步非阻塞
        data = ''
        for fileno, event in events:
            data += sys.stdin.readline() # 通过标准输入获取数据
            if data == '' or data == '\n':
                continue
            items = xxx # 数处理过程
            for item in items:
                result = mbe.get(item)
                sys.stdout.write(json.dumps(result, ensure_ascii=False) +'\n') # 写入到标准输出
                sys.stdout.flush() # 缓冲区刷新
finally:
    epoll.unregister(fd)
    epoll.close()

index.js - 通过 stdin 发送数据

const child_process = require('child_process');
const child = child_process.spawn('python3', ['./base.py']);

let callbacks =  [], 
    chunks=Buffer.alloc(0), 
    chunkArr = [], 
    data = '', 
    onwork = false; // buffer 无法动态扩容
    
child.stdout.on('data', (chunk) => {
    chunkArr.push(chunk)
    if (onwork) return;
    onwork = true;
    while(chunkArr.length) {
        chunks = Buffer.concat([chunks, chunkArr.pop()]);
        const length = chunks.length;
        let trunkAt = -1;
        for(const [k, d] of chunks.entries()) {
            if (d == '0x0a') { // 0a 结尾
                data += chunks.slice(trunkAt+1, trunkAt=k);
                const cb = callbacks.shift();
                cb(null, data === 'null' ? null : data )
                data = '';
            }
        }
        if (trunkAt < length) {
            chunks = chunks.slice(trunkAt+1)
        }
    }
    onwork = false;
})

setInterval(() => {
    if (callbacks.length) child.stdin.write(`\n`); // Nodejs端的标准输入输出没有flush方法,只能 hack, 写入后python无法及时获取到最新
}, 500)

exports.getMsg = function getMsg(ip, cb) {
    callbacks.push(cb)
    child.stdin.write(`${ip}\n`); // 把数据写入到子进程的标准输入
}

Python 与 Nodejs 通过 stdio 实现通信; Python 通过 epoll 监听 stdin 实现驻留内存,长时间运行。

存在问题

  • Nodejs 把标准输出作为执行结果,故 Python 端只能把执行结果写入标准输出,不能有额外的打印信息
  • Nodejs 端标准输入没有 flush 方法,所以 Python 端事件触发不够及时,目前通过在Nodejs端定时发送空信息来 hack 实现
  • Buffer 没法动态扩容,没有C语言的指针好用,在解析 stdout 时写丑

总结

虽然可以实现 Nodejs 和 Python 的双向通信,然后由于上述种种问题,在这里并不推荐使用这种方式,通过 HTTP 或 Socket 方式比这个香多了。

到此这篇关于Nodejs与Python 双向通信的实现代码的文章就介绍到这了,更多相关Nodejs与Python双向通信内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JS 控制小数位数的实现代码
Aug 02 Javascript
Javascript WebSocket使用实例介绍(简明入门教程)
Apr 16 Javascript
javascript进行数组追加方法小结
Jun 16 Javascript
Javascript堆排序算法详解
Dec 03 Javascript
js字符串操作方法实例分析
May 06 Javascript
全面解析Bootstrap布局组件应用
Feb 22 Javascript
JavaScript中const、var和let区别浅析
Oct 11 Javascript
js前端导出Excel的方法
Nov 01 Javascript
如何编写一个d.ts文件的步骤详解
Apr 13 Javascript
vue 返回上一页,页面样式错乱的解决
Nov 14 Javascript
vue中实现图片压缩 file文件的方法
May 28 Javascript
详解TS数字分隔符和更严格的类属性检查
May 06 Javascript
node.js如何自定义实现一个EventEmitter
Jul 16 #Javascript
node.js使用express-fileupload中间件实现文件上传
Jul 16 #Javascript
html5 录制mp3音频支持采样率和比特率设置
js基础语法与maven项目配置教程案例
JavaScript与JQuery框架基础入门教程
Jul 15 #Javascript
Python机器学习之决策树和随机森林
微信小程序scroll-view不能左右滑动问题的解决方法
You might like
php下保存远程图片到本地的办法
2010/08/08 PHP
PHP+Mysql日期时间如何转换(UNIX时间戳和格式化日期)
2012/07/15 PHP
原生JS实现Ajax通过POST方式与PHP进行交互的方法示例
2018/05/12 PHP
JavaScript高级程序设计 学习笔记 js高级技巧
2011/09/20 Javascript
Javascript图像处理—平滑处理实现原理
2012/12/28 Javascript
js和jquery中循环的退出和继续学习记录
2014/09/06 Javascript
javascript实现简单的省市区三级联动
2015/05/14 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
js实现canvas保存图片为png格式并下载到本地的方法
2017/08/31 Javascript
详解jQuery中的isPlainObject()使用方法
2018/02/27 jQuery
浅谈Vue内置component组件的应用场景
2018/03/27 Javascript
vue v-model动态生成详解
2018/06/30 Javascript
JQuery animate动画应用示例
2019/05/14 jQuery
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
python网络爬虫采集联想词示例
2014/02/11 Python
Python解析网页源代码中的115网盘链接实例
2014/09/30 Python
Python函数参数类型*、**的区别
2015/04/11 Python
Python备份目录及目录下的全部内容的实现方法
2016/06/12 Python
Python中运算符&quot;==&quot;和&quot;is&quot;的详解
2016/10/08 Python
Python 序列的方法总结
2016/10/18 Python
Python中static相关知识小结
2018/01/02 Python
python rsync服务器之间文件夹同步脚本
2019/08/29 Python
详解python opencv、scikit-image和PIL图像处理库比较
2019/12/26 Python
PyQt5实现仿QQ贴边隐藏功能的实例代码
2020/05/24 Python
香港太阳眼镜网上商店:SmartBuyGlasses香港
2016/07/22 全球购物
运动服饰每月订阅盒:Ellie
2018/04/29 全球购物
Diesel美国网上商店:意大利牛仔时装品牌
2020/12/10 全球购物
工业学校毕业生自荐信范文
2014/01/03 职场文书
公司前台辞职报告
2014/01/19 职场文书
初中生操行评语大全
2014/04/24 职场文书
《山谷中的谜底》教学反思
2014/04/26 职场文书
向国旗敬礼活动小结
2014/09/27 职场文书
2015毕业实习推荐信
2015/03/23 职场文书
社区低保工作总结2015
2015/07/23 职场文书
2015年七夕情人节感言
2015/08/03 职场文书
关于MybatisPlus配置双数据库驱动连接数据库问题
2022/01/22 Java/Android