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剩余字数计算的代码
Jul 03 Javascript
根据表格中的某一列进行排序的javascript代码
Nov 29 Javascript
html5+javascript制作简易画板附图
Apr 25 Javascript
javascript实现列表滚动的方法
Jul 30 Javascript
JavaScript继承模式粗探
Jan 12 Javascript
写给vue新手们的vue渲染页面教程
Sep 01 Javascript
vue2.0 路由不显示router-view的解决方法
Mar 06 Javascript
Vue keepAlive 数据缓存工具实现返回上一个页面浏览的位置
May 10 Javascript
javascript数组常见操作方法实例总结【连接、添加、删除、去重、排序等】
Jun 13 Javascript
javascript中call,apply,callee,caller用法实例分析
Jul 24 Javascript
vue实现百度搜索功能
Dec 28 Javascript
js生成1到100的随机数最简单的实现方法
Feb 07 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读取EXCEL文件 php excelreader读取excel文件
2012/12/06 PHP
php中flush()、ob_flush()、ob_end_flush()的区别介绍
2013/02/17 PHP
php采集文章中的图片获取替换到本地(实现代码)
2013/07/08 PHP
jQuery ajax+PHP实现的级联下拉列表框功能示例
2019/02/12 PHP
Thinkphp5.0 框架的请求方式与响应方式分析
2019/10/14 PHP
一个基于jquery的图片切换效果
2010/07/06 Javascript
对JavaScript中this指针的新理解分享
2015/01/31 Javascript
jquery+css3实现网页背景花瓣随机飘落特效
2015/08/17 Javascript
完美JQuery图片切换效果的简单实现
2016/07/21 Javascript
Bootstrap表单简单实现代码
2017/03/06 Javascript
jQuery表单验证之密码确认
2017/05/22 jQuery
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
对node.js中render和send的用法详解
2018/05/14 Javascript
JavaScript中this关键字用法实例分析
2018/08/24 Javascript
使用xampp将angular项目运行在web服务器的教程
2019/09/16 Javascript
Python中SOAP项目的介绍及其在web开发中的应用
2015/04/14 Python
在Linux下使用Python的matplotlib绘制数据图的教程
2015/06/11 Python
python获取外网ip地址的方法总结
2015/07/02 Python
python 通过 socket 发送文件的实例代码
2018/08/14 Python
python批量复制图片到另一个文件夹
2018/09/17 Python
python实现H2O中的随机森林算法介绍及其项目实战
2019/08/29 Python
PyCharm MySQL可视化Database配置过程图解
2020/06/09 Python
Python select及selectors模块概念用法详解
2020/06/22 Python
Selenium关闭INFO:CONSOLE提示的解决
2020/12/07 Python
HTML5 canvas画矩形时出现边框样式不一致的解决方法
2013/10/14 HTML / CSS
美国创意之家:BulbHead
2017/07/12 全球购物
名人珠宝设计师:Melinda Maria Jewelry
2019/03/06 全球购物
网络事业创业计划书范文
2014/01/09 职场文书
公务员保密承诺书
2014/03/27 职场文书
幼儿园大班教师个人总结
2015/02/05 职场文书
2015年学校食堂工作总结
2015/04/22 职场文书
2015年行政助理工作总结
2015/04/30 职场文书
暑期辅导班宣传单
2015/07/14 职场文书
python cv2图像质量压缩的算法示例
2021/06/04 Python
关于React Native 无法链接模拟器的问题
2021/06/21 Javascript
vue3引入highlight.js进行代码高亮的方法实例
2022/04/08 Vue.js