重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要介绍“Node与Python双向通信如何实现”,在日常操作中,相信很多人在Node与Python双向通信如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Node与Python双向通信如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
成都创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都做网站、成都网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的榆林网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
第三方数据供应商把数据和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 == " ": continue items = xxx # 数处理过程 for item in items: result = mbe.get(item) sys.stdout.write(json.dumps(result, ensure_ascii=False) +" ") # 写入到标准输出 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(` `); // Nodejs端的标准输入输出没有flush方法,只能 hack, 写入后python无法及时获取到最新 }, 500) exports.getMsg = function getMsg(ip, cb) { callbacks.push(cb) child.stdin.write(`${ip} `); // 把数据写入到子进程的标准输入 }
Python 与 Nodejs 通过 stdio 实现通信; Python 通过 epoll 监听 stdin 实现驻留内存,长时间运行。
Nodejs 把标准输出作为执行结果,故 Python 端只能把执行结果写入标准输出,不能有额外的打印信息
Nodejs 端标准输入没有 flush 方法,所以 Python 端事件触发不够及时,目前通过在Nodejs端定时发送空信息来 hack 实现
Buffer 没法动态扩容,没有C语言的指针好用,在解析 stdout 时写丑
到此,关于“Node与Python双向通信如何实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!