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模仿windows桌面图标排列算法具体实现(附图)
Jun 16 Javascript
js网页版计算器的简单实现
Jul 02 Javascript
Jquery 例外被抛出且未被接住原因介绍
Sep 04 Javascript
键盘KeyCode值列表汇总
Nov 26 Javascript
JavaScript实现的SHA-1加密算法完整实例
Feb 02 Javascript
神奇!js+CSS+DIV实现文字颜色渐变效果
Mar 16 Javascript
JS中with的替代方法与String中的正则方法详解
Dec 23 Javascript
VueJs单页应用实现微信网页授权及微信分享功能示例
Jul 26 Javascript
微信小程序swiper组件用法实例分析【附源码下载】
Dec 07 Javascript
javascript中函数的写法实例代码详解
Oct 28 Javascript
vue实现公共方法抽离
Jul 31 Javascript
Vue 打包后相对路径的引用问题
Jun 05 Vue.js
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
thinkphp3.2.3 分页代码分享
2016/07/28 PHP
ThinkPHP 整合Bootstrap Ajax分页样式
2016/12/23 PHP
Yii2实现多域名跨域同步登录退出
2017/02/04 PHP
PHP编程实现脚本异步执行的方法
2017/08/09 PHP
php使用lua+redis实现限流,计数器模式,令牌桶模式
2019/04/04 PHP
PHP防止sql注入小技巧之sql预处理原理与实现方法分析
2019/12/13 PHP
jquery.cookie.js 操作cookie实现记住密码功能的实现代码
2011/04/27 Javascript
jquery图片放大功能简单实现
2013/08/01 Javascript
JQuery+Ajax无刷新分页的实例代码
2014/02/08 Javascript
深入理解Javascript里的依赖注入
2014/03/19 Javascript
基于Jquery实现键盘按键监听
2014/05/11 Javascript
JavaScript里四舍五入函数round用法实例
2015/04/06 Javascript
JS 作用域与作用域链详解
2015/04/07 Javascript
jquery获取多个checkbox的值异步提交给php
2015/07/07 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
2016/05/13 Javascript
javascript帧动画(实例讲解)
2017/09/02 Javascript
用js简单提供增删改查接口
2019/05/12 Javascript
Node.js API详解之 util模块用法实例分析
2020/05/09 Javascript
vue-router定义元信息meta操作
2020/12/07 Vue.js
Vue——解决报错 Computed property &quot;****&quot; was assigned to but it has no setter.
2020/12/19 Vue.js
[36:16]完美世界DOTA2联赛PWL S3 access vs Rebirth 第一场 12.19
2020/12/24 DOTA
python抓取网页内容示例分享
2014/02/24 Python
浅析Python中的多重继承
2015/04/28 Python
Python中的条件判断语句与循环语句用法小结
2016/03/21 Python
浅析Django中关于session的使用
2019/12/30 Python
用HTML5实现网站在windows8中贴靠的方法
2013/04/21 HTML / CSS
Gloeilampgoedkoop荷兰:在线购买灯泡
2019/02/16 全球购物
大学生创业感言
2014/01/25 职场文书
感恩之星事迹材料
2014/05/03 职场文书
学生干部培训方案
2014/06/12 职场文书
党员批评与自我批评(5篇)
2014/09/23 职场文书
2015年安置帮教工作总结
2015/05/22 职场文书
新年寄语2016
2015/08/17 职场文书
医务人员岗前培训心得体会
2016/01/08 职场文书
javascript对象3个属性特征
2021/11/17 Javascript
golang生成并解析JSON
2022/04/14 Golang