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 相关文章推荐
利用javascript解决图片缩放及其优化的代码
May 23 Javascript
js加密解密字符串可自定义密码因子
May 13 Javascript
纯js和css实现渐变色包括静态渐变和动态渐变
May 29 Javascript
基于javascript实现句子翻牌网页版小游戏
Mar 23 Javascript
Bootstrap媒体对象的实现
May 01 Javascript
js实现表格筛选功能
Jan 18 Javascript
vue中for循环更改数据的实例代码(数据变化但页面数据未变)
Sep 15 Javascript
JS Testing Properties 判断属性是否在对象里的方法
Oct 01 Javascript
vant(ZanUi)结合async-validator实现表单验证的方法
Dec 06 Javascript
webpack file-loader和url-loader的区别
Jan 15 Javascript
vue移动端实现手机左右滑动入场动画
Jun 17 Javascript
浅谈Node新版本13.2.0正式支持ES Modules特性
Nov 25 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 异常处理实现代码
2009/03/10 PHP
php获得用户ip地址的比较不错的方法
2014/02/08 PHP
PHP获取文件行数的方法
2015/06/10 PHP
ThinkPHP静态缓存简单配置和使用方法详解
2016/03/23 PHP
PHP动态地创建属性和方法, 对象的复制, 对象的比较,加载指定的文件,自动加载类文件,命名空间
2016/05/06 PHP
PHP实现将MySQL重复ID二维数组重组为三维数组的方法
2016/08/01 PHP
php脚本守护进程原理与实现方法详解
2017/07/20 PHP
Firefox下提示illegal character并出现乱码的原因
2010/03/25 Javascript
js 金额文本框实现代码
2012/02/14 Javascript
Javascript 实现图片无缝滚动
2014/12/19 Javascript
深入浅析JSON.parse()、JSON.stringify()和eval()的作用详解
2016/04/03 Javascript
jQuery实现的表格展开伸缩效果实例
2016/09/07 Javascript
JavaScript学习笔记整理_用于模式匹配的String方法
2016/09/19 Javascript
Vue中之nextTick函数源码分析详解
2017/10/17 Javascript
详解vue-cli 快速搭建单页应用之遇到的问题及解决办法
2018/03/01 Javascript
js实现黑白div块画空心的图形
2018/12/13 Javascript
node.JS路径解析之PATH模块使用方法详解
2020/02/06 Javascript
基于Web Audio API实现音频可视化效果
2020/06/12 Javascript
javascript实现多边形碰撞检测
2020/10/24 Javascript
[44:39]2014 DOTA2国际邀请赛中国区预选赛 NE VS CNB
2014/05/21 DOTA
python聊天程序实例代码分享
2013/11/18 Python
python中引用与复制用法实例分析
2015/06/04 Python
Fiddler如何抓取手机APP数据包
2016/01/22 Python
Python面向对象编程基础解析(二)
2017/10/26 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
2018/04/18 Python
浅谈Python中的bs4基础
2018/10/21 Python
PyTorch加载自己的数据集实例详解
2020/03/18 Python
python将unicode和str互相转化的实现
2020/05/11 Python
Pycharm自带Git实现版本管理的方法步骤
2020/09/18 Python
scrapy头部修改的方法详解
2020/12/06 Python
垃圾回收的优点和原理。并考虑2种回收机制
2016/10/16 面试题
在校大学生个人的自我评价
2014/02/13 职场文书
私营公司诉讼代理委托书范本
2014/09/13 职场文书
贷款收入证明格式
2015/06/24 职场文书
python编程简单几行代码实现视频转换Gif示例
2021/10/05 Python
Python 数据可视化工具 Pyecharts 安装及应用
2022/04/20 Python