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 css float属性的特殊写法
Nov 13 Javascript
类似CSDN图片切换效果脚本
Sep 17 Javascript
dojo学习第二天 ajax异步请求之绑定列表
Aug 29 Javascript
无缝滚动改进版支持上下左右滚动(封装成函数)
Dec 04 Javascript
关于jquery的多个选择器的使用示例
Oct 18 Javascript
javascript匿名函数应用示例介绍
Mar 07 Javascript
单击按钮发送验证码,出现倒计时的简单实例
Mar 17 Javascript
JS实现简易的图片拖拽排序实例代码
Jun 09 Javascript
Node.js实现连接mysql数据库功能示例
Sep 15 Javascript
react-native组件中NavigatorIOS和ListView结合使用的方法
Sep 30 Javascript
Angular实现的敏感文字自动过滤与提示功能示例
Dec 29 Javascript
vue :src 文件路径错误问题的解决方法
May 15 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 无限级数据JSON格式及JS解析
2010/07/17 PHP
PHP面向对象的进阶学习(抽像类、接口、final、类常量)
2012/05/07 PHP
smarty模板引擎中自定义函数的方法
2015/01/22 PHP
php实现图片上传并利用ImageMagick生成缩略图
2016/03/14 PHP
php版微信公众平台之微信网页登陆授权示例
2016/09/23 PHP
PHP检查网站是否宕机的方法示例
2017/07/24 PHP
Laravel框架路由管理简单示例
2019/05/07 PHP
基于PHP实现生成随机水印图片
2020/12/09 PHP
BOOM vs RR BO5 第一场 2.14
2021/03/10 DOTA
js 代码优化点滴记录
2012/02/19 Javascript
JavaScript中instanceof与typeof运算符的用法及区别详细解析
2013/11/19 Javascript
jQuery中siblings()方法用法实例
2015/01/08 Javascript
浅析JavaScript 调试方法和技巧
2015/10/22 Javascript
jQuery Mobile 和 Kendo UI 的比较
2016/05/05 Javascript
原生js实现倒计时--2018
2017/02/21 Javascript
微信小程序 登录的简单实现
2017/04/19 Javascript
利用HBuilder打包前端开发webapp为apk的方法
2017/11/13 Javascript
vue中tab选项卡的实现思路
2018/11/25 Javascript
BootStrap模态框闪退问题实例代码详解
2018/12/10 Javascript
js时间转换毫秒的实例代码
2019/08/21 Javascript
antd-mobile ListView长列表的数据更新遇到的坑
2020/04/08 Javascript
react中hook介绍以及使用教程
2020/12/11 Javascript
python web基础之加载静态文件实例
2018/03/20 Python
python 3调用百度OCR API实现剪贴板文字识别
2018/09/04 Python
Python爬虫将爬取的图片写入world文档的方法
2018/11/07 Python
Python限制内存和CPU使用量的方法(Unix系统适用)
2020/08/04 Python
深入探究HTML5的History API
2015/07/09 HTML / CSS
自1926年以来就为冰岛保持温暖:66°North
2020/11/27 全球购物
现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset
2012/11/09 面试题
应聘文员自荐信范文
2014/03/11 职场文书
党员个人批评与自我批评
2014/10/14 职场文书
市场部岗位职责范本
2015/04/15 职场文书
保险公司反洗钱宣传活动总结
2015/05/08 职场文书
2019求职信大礼包
2019/05/15 职场文书
电脑关机速度很慢怎么办 提升电脑关机速度设置教程
2022/04/08 数码科技
Python中time标准库的使用教程
2022/04/13 Python