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 相关文章推荐
jquery移除button的inline onclick事件(已测试及兼容浏览器)
Jan 25 Javascript
跟我学习javascript的作用域与作用域链
Nov 19 Javascript
jquery实现点击其他区域时隐藏下拉div和遮罩层的方法
Dec 23 Javascript
jQuery soColorPacker 网页拾色器
Jun 22 Javascript
JavaScript实现通过select标签跳转网页的方法
Sep 29 Javascript
最好用的Bootstrap fileinput.js文件上传组件
Dec 12 Javascript
springMVC + easyui + $.ajaxFileUpload实现文件上传注意事项
Apr 23 Javascript
JS中的数组转变成JSON格式字符串的方法
May 09 Javascript
fullpage.js最后一屏滚动方式
Feb 06 Javascript
IE11下处理Promise及Vue的单项数据流问题
Jul 24 Javascript
js图数据结构处理 迪杰斯特拉算法代码实例
Sep 11 Javascript
Javascript设计模式之原型模式详细
Oct 05 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
JavaScript脚本性能的优化方法
2007/02/02 Javascript
javascript 检测浏览器类型和版本的代码
2009/09/15 Javascript
jquery.lazyload  实现图片延迟加载jquery插件
2010/02/06 Javascript
javascript 隐藏/显示指定的区域附HTML元素【legend】用法
2010/03/05 Javascript
safari,opera嵌入iframe页面cookie读取问题解决方法
2010/06/23 Javascript
鼠标滑上去后图片放大浮出效果的js代码
2011/05/28 Javascript
js 动态修改css文件用到了cssRule
2014/08/20 Javascript
AngularJS基础学习笔记之控制器
2015/05/10 Javascript
javascript实现的网站访问量统计代码
2015/12/20 Javascript
jQuery autoComplete插件两种使用方式及动态改变参数值的方法详解
2016/10/24 Javascript
微信小程序 wx.request(接口调用方式)详解及实例
2016/11/23 Javascript
jQuery实现链接的title快速出现的方法
2017/02/20 Javascript
JavaScript中双符号的运算详解
2017/03/12 Javascript
vue.js层叠轮播效果的实例代码
2018/11/08 Javascript
vue中的v-if和v-show的区别详解
2019/09/01 Javascript
es5 类与es6中class的区别小结
2020/11/09 Javascript
python中threading超线程用法实例分析
2015/05/16 Python
深入解析Python中的线程同步方法
2016/06/14 Python
python 简单搭建阻塞式单进程,多进程,多线程服务的实例
2017/11/01 Python
python中join()方法介绍
2018/10/11 Python
python3中类的继承以及self和super的区别详解
2019/06/26 Python
Python使用微信itchat接口实现查看自己微信的信息功能详解
2019/08/22 Python
Python数据处理篇之Sympy系列(五)---解方程
2019/10/12 Python
python GUI库图形界面开发之PyQt5中QWebEngineView内嵌网页与Python的数据交互传参详细方法实例
2020/02/26 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
2020/06/03 Python
高中化学教学反思
2014/01/13 职场文书
职工运动会邀请函
2014/01/19 职场文书
网络技术专业推荐信
2014/02/20 职场文书
本科毕业论文导师评语
2014/12/31 职场文书
继承公证书格式
2015/01/26 职场文书
2015教师年度考核评语
2015/03/25 职场文书
2015年公路路政个人工作总结
2015/07/24 职场文书
战友聚会致辞
2015/07/28 职场文书
《雷雨》教学反思
2016/02/20 职场文书
工作一年自我鉴定
2019/06/20 职场文书
2019最新激励员工口号大全!
2019/06/28 职场文书