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 相关文章推荐
formStorage 基于jquery的一个插件(存储表单中元素的状态到本地)
Jan 20 Javascript
Jquery UI震动效果实现原理及步骤
Feb 04 Javascript
禁用键盘上的(全局)指定键兼容iE、Chrome、火狐
May 14 Javascript
window.opener用法和用途实例介绍
Aug 19 Javascript
用jQuery实现的智能隐藏、滑动效果的返回顶部代码
Mar 18 Javascript
JS实现进入页面时渐变背景色的方法
Feb 25 Javascript
JavaScript中常见的字符串操作函数及用法汇总
May 04 Javascript
一步一步封装自己的HtmlHelper组件BootstrapHelper(二)
Sep 14 Javascript
jQuery 操作 HTML 元素和属性的方法
Nov 12 jQuery
JS 自执行函数原理及用法
Aug 05 Javascript
解决ant Design Search无法输入内容的问题
Oct 29 Javascript
小程序自定义轮播图圆点组件
Jun 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 防恶意刷新实现代码
2010/05/16 PHP
很全的显示阴历(农历)日期的js代码
2009/01/01 Javascript
JavaScript中两种链式调用实现代码
2011/01/12 Javascript
JavaScript中对象属性的添加和删除示例
2014/05/12 Javascript
node.js中的fs.ftruncate方法使用说明
2014/12/15 Javascript
2则自己编写的jQuery特效分享
2015/02/26 Javascript
JavaScript改变CSS样式的方法汇总
2015/05/07 Javascript
基于JavaScript判断浏览器到底是关闭还是刷新(超准确)
2016/02/01 Javascript
jQuery添加options点击事件并传值实例代码
2016/05/18 Javascript
学习使用Bootstrap输入框、导航、分页等常用组件
2017/05/11 Javascript
JavaScript获取tr td 的三种方式全面总结(推荐)
2017/08/15 Javascript
jQuery自动或手动图片切换效果
2017/10/11 jQuery
react 国际化的实现代码示例
2018/09/14 Javascript
浅谈Javascript中的对象和继承
2019/04/19 Javascript
JS数组扁平化(flat)方法总结详解
2019/06/24 Javascript
vue中npm包全局安装和局部安装过程
2019/09/03 Javascript
js实现随机点名程序
2020/09/17 Javascript
[00:17]DOTA2荣耀之路5:It’s a disastah!
2018/05/28 DOTA
Python编程之属性和方法实例详解
2015/05/19 Python
CentOS 6.5中安装Python 3.6.2的方法步骤
2017/12/03 Python
python绘制简单折线图代码示例
2017/12/19 Python
Python实现微信小程序支付功能
2019/07/25 Python
html5 button autofocus 属性介绍及应用
2013/01/04 HTML / CSS
HTML利用九宫格原理进行网页布局
2020/03/13 HTML / CSS
AE美国鹰日本官方网站: American Eagle Outfitters
2016/12/10 全球购物
Chemist Warehouse官方海外旗舰店:澳洲第一连锁大药房
2017/08/25 全球购物
TheFork葡萄牙:欧洲领先的在线餐厅预订平台
2019/05/27 全球购物
Bibloo罗马尼亚网站:女装、男装、童装及鞋子和配饰
2019/07/20 全球购物
中东最大的在线宠物店:Dubai Pet Food
2020/06/11 全球购物
小学教师事迹材料
2014/01/13 职场文书
副科竞争上岗演讲稿
2014/05/12 职场文书
2014幼儿园家长工作总结
2014/11/10 职场文书
歼十出击观后感
2015/06/11 职场文书
2015年学校总务工作总结
2015/07/20 职场文书
标准演讲稿格式结尾应该怎么书写?
2019/07/17 职场文书
CSS3通过var()和calc()函数实现动画特效
2021/03/30 HTML / CSS