Node與Python 雙向通信的實(shí)現(xiàn)代碼
第三方數(shù)據(jù)供應(yīng)商把數(shù)據(jù)和Python封裝到一起,只能通過調(diào)用 Python方法來實(shí)現(xiàn)數(shù)據(jù)查詢,如果可以通過Node 簡單封裝下實(shí)現(xiàn) Python 方法調(diào)用可以快速上線并節(jié)省開發(fā)成本。
最簡單粗暴的通信方式是 Nodejs調(diào)用一下 Python 腳本,然后獲取子進(jìn)程的輸出,但是由于每次 Python 啟動(dòng)并加載數(shù)據(jù)包的過程比較漫長,所以對(duì)該過程優(yōu)化。
進(jìn)程通信
index.py
# 封裝的 Python 包, 體積巨大
from mb import MB
# 從數(shù)據(jù)包中查詢
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 子進(jìn)程,監(jiān)聽 stdout 輸出。上述方式也是官方文檔中的示例,目前該示例存在兩個(gè)問題:
- Nodejs 沒有向 Python 發(fā)送數(shù)據(jù)
- Nodejs 調(diào)用完畢后,Python 子進(jìn)程會(huì)退出;下次查詢需要再次調(diào)用Python命令進(jìn)行加載文件,查詢數(shù)據(jù);無法實(shí)現(xiàn)一次內(nèi)存加載,多次使用。
進(jìn)程雙向通信
保證一次數(shù)據(jù)加載,多次使用的前提是 Python 進(jìn)程啟動(dòng)后不能退出。Python 進(jìn)程之所以退出是因?yàn)闊o事可做,所以常見的手段有循環(huán),sleep,監(jiān)聽端口,這些手段可以翻譯成同步阻塞任務(wù),同步非阻塞任務(wù),其中代價(jià)最小的就是同步非阻塞任務(wù),然后可以想到 Linux 的 select,epoll,簡單搜索了下 Python 的 epoll,好像還有原生的包。
index.py - 通過 epoll 監(jiān)聽 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() # 通過標(biāo)準(zhǔn)輸入獲取數(shù)據(jù)
if data == '' or data == '\n':
continue
items = xxx # 數(shù)處理過程
for item in items:
result = mbe.get(item)
sys.stdout.write(json.dumps(result, ensure_ascii=False) +'\n') # 寫入到標(biāo)準(zhǔn)輸出
sys.stdout.flush() # 緩沖區(qū)刷新
finally:
epoll.unregister(fd)
epoll.close()
index.js - 通過 stdin 發(fā)送數(shù)據(jù)
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 無法動(dòng)態(tài)擴(kuò)容
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 結(jié)尾
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端的標(biāo)準(zhǔn)輸入輸出沒有flush方法,只能 hack, 寫入后python無法及時(shí)獲取到最新
}, 500)
exports.getMsg = function getMsg(ip, cb) {
callbacks.push(cb)
child.stdin.write(`${ip}\n`); // 把數(shù)據(jù)寫入到子進(jìn)程的標(biāo)準(zhǔn)輸入
}
Python 與 Nodejs 通過 stdio 實(shí)現(xiàn)通信; Python 通過 epoll 監(jiān)聽 stdin 實(shí)現(xiàn)駐留內(nèi)存,長時(shí)間運(yùn)行。
存在問題
- Nodejs 把標(biāo)準(zhǔn)輸出作為執(zhí)行結(jié)果,故 Python 端只能把執(zhí)行結(jié)果寫入標(biāo)準(zhǔn)輸出,不能有額外的打印信息
- Nodejs 端標(biāo)準(zhǔn)輸入沒有 flush 方法,所以 Python 端事件觸發(fā)不夠及時(shí),目前通過在Nodejs端定時(shí)發(fā)送空信息來 hack 實(shí)現(xiàn)
- Buffer 沒法動(dòng)態(tài)擴(kuò)容,沒有C語言的指針好用,在解析 stdout 時(shí)寫丑
總結(jié)
雖然可以實(shí)現(xiàn) Nodejs 和 Python 的雙向通信,然后由于上述種種問題,在這里并不推薦使用這種方式,通過 HTTP 或 Socket 方式比這個(gè)香多了。
到此這篇關(guān)于Nodejs與Python 雙向通信的實(shí)現(xiàn)代碼的文章就介紹到這了,更多相關(guān)Nodejs與Python雙向通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于Node.js和Socket.IO實(shí)現(xiàn)實(shí)時(shí)通信功能
- 淺析如何在Bash中調(diào)用Node運(yùn)行JS文件進(jìn)行數(shù)據(jù)通信
- Node.js中的進(jìn)程間通信
- 基于node的tcp客戶端和服務(wù)端的簡單通信
- Nodejs環(huán)境實(shí)現(xiàn)socket通信過程解析
- node實(shí)現(xiàn)socket鏈接與GPRS進(jìn)行通信的方法
- node 利用進(jìn)程通信實(shí)現(xiàn)Cluster共享內(nèi)存
- Node.js進(jìn)行串口通信的實(shí)現(xiàn)示例
相關(guān)文章
使用Nodejs編寫一個(gè)腳本實(shí)現(xiàn)markdown轉(zhuǎn)pdf功能
Markdown?是一種輕量級(jí)的標(biāo)記語言,非常適合用來寫作和記錄,將?Markdown?轉(zhuǎn)換為?PDF?可以讓文檔在格式和樣式上更加統(tǒng)一,也方便在不同設(shè)備和平臺(tái)上查看和打印,在接下來的內(nèi)容中我們將講解如何使用?NodeJs?編寫一個(gè)?Markdown?轉(zhuǎn)?PDF?的腳本來實(shí)現(xiàn)我們這個(gè)想要的功能2024-05-05
Node.js模擬發(fā)起http請(qǐng)求從異步轉(zhuǎn)同步的5種用法
這篇文章主要介紹了Node.js模擬發(fā)起http請(qǐng)求從異步轉(zhuǎn)同步的5種方法,下面總結(jié)了幾個(gè)常見的庫 API 從異步轉(zhuǎn)同步的幾種方法。需要的朋友可以參考下2018-09-09
nodejs基礎(chǔ)之buffer緩沖區(qū)用法分析
這篇文章主要介紹了nodejs基礎(chǔ)之buffer緩沖區(qū)用法,結(jié)合實(shí)例形式分析了buffer緩沖區(qū)的概念、功能、創(chuàng)建、讀寫等相關(guān)操作技巧,需要的朋友可以參考下2018-12-12
nodejs之get/post請(qǐng)求的幾種方式小結(jié)
下面小編就為大家?guī)硪黄猲odejs之get/post請(qǐng)求的幾種方式小結(jié)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
nodejs版本過高導(dǎo)致vue-cli項(xiàng)目無法正常運(yùn)行的幾種解決方案
這篇文章主要給大家介紹了關(guān)于nodejs版本過高導(dǎo)致vue-cli項(xiàng)目無法正常運(yùn)行的幾種解決方案,在項(xiàng)目中你可能需要用到的node版本太低,但是你所下的node版本是最新的,這時(shí)候就會(huì)報(bào)錯(cuò),需要的朋友可以參考下2023-07-07
詳解nodejs實(shí)現(xiàn)本地上傳圖片并預(yù)覽功能(express4.0+)
本篇文章主要介紹了nodejs實(shí)現(xiàn)本地上傳圖片并預(yù)覽功能(express4.0+) ,具有一定的參考價(jià)值,有興趣的可以了解一下2017-06-06
Node.js在child_process域和錯(cuò)誤冒泡及捕獲實(shí)踐
這篇文章主要為大家介紹了Node.js在child_process域和錯(cuò)誤冒泡及捕獲實(shí)踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

