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 引起的安全问题
Dec 27 Javascript
javascript最常用与实用的创建类的代码
Aug 12 Javascript
js事件冒泡实例分享(已测试)
Apr 23 Javascript
ExtJS判断IE浏览器类型的方法
Feb 10 Javascript
jquery选择器简述
Aug 31 Javascript
jquery限定文本框只能输入数字(整数和小数)
Jan 08 Javascript
使用JavaScript实现ajax的实例代码
May 11 Javascript
基于gulp合并压缩Seajs模块的方式说明
Jun 14 Javascript
浅谈JS正则表达式的RegExp对象和括号的使用
Jul 28 Javascript
textarea 在浏览器中固定大小和禁止拖动的实现方法
Dec 03 Javascript
使用Javascript判断浏览器终端设备(PC、IOS(iphone)、Android)
Jan 04 Javascript
浅谈vuex的基本用法和mapaction传值问题
Nov 08 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 实例化类的一点摘记
2008/03/23 PHP
PHP和Mysqlweb应用开发核心技术 第1部分 Php基础-1 开始了解php
2011/07/03 PHP
php中将图片gif,jpg或mysql longblob或blob字段值转换成16进制字符串
2011/08/23 PHP
session在php5.3中的变化 session_is_registered() is deprecated in
2013/11/12 PHP
利用PHP命令行模式采集股票趋势信息
2016/08/09 PHP
js优化针对IE6.0起作用(详细整理)
2012/12/25 Javascript
jQuery使用动态渲染表单功能完成ajax文件下载
2013/01/15 Javascript
jQuery多项选项卡的实现思路附样式及代码
2014/06/03 Javascript
jQuery插件StickUp实现网页导航置顶
2015/04/12 Javascript
jQuery超赞的评分插件(8款)
2015/08/20 Javascript
快速学习JavaScript的6个思维技巧
2015/10/13 Javascript
JS实现网页游戏中滑块响应鼠标点击移动效果
2015/10/19 Javascript
JavaScript代码实现禁止右键、禁选择、禁粘贴、禁shift、禁ctrl、禁alt
2015/11/17 Javascript
Bootstrap轮播插件中图片变形的终极解决方案 使用jqthumb.js
2016/07/10 Javascript
js实现上传图片预览方法
2016/10/25 Javascript
解决同一页面中两个iframe互相调用jquery,js函数的方法
2016/12/12 Javascript
Node.js的特点详解
2017/02/03 Javascript
JS基于正则截取替换特定字符之间字符串操作示例
2017/02/03 Javascript
详解angular中通过$location获取路径(参数)的写法
2017/03/21 Javascript
javascript 内存模型实例详解
2020/04/18 Javascript
js实现圆形菜单选择器
2020/12/03 Javascript
详解MySQL数据类型int(M)中M的含义
2016/11/20 Python
Python的numpy库中将矩阵转换为列表等函数的方法
2018/04/04 Python
python如何创建TCP服务端和客户端
2018/08/26 Python
django 模型字段设置默认值代码
2020/07/15 Python
教师评优的个人自我评价分享
2013/09/19 职场文书
应用化学专业职业生涯规划书
2013/12/31 职场文书
初中体育教学反思
2014/01/14 职场文书
英文求职信写作小建议
2014/02/16 职场文书
维修工先进事迹
2014/05/29 职场文书
销售简历自我评价怎么写
2014/09/26 职场文书
个人整改措施落实情况汇报
2014/10/29 职场文书
2014年乡镇个人工作总结
2014/12/03 职场文书
祝福语集锦:朋友新店开业祝福语
2019/12/10 职场文书
浅谈自定义校验注解ConstraintValidator
2021/06/30 Java/Android
SQL Server Agent 服务无法启动
2022/04/20 SQL Server