1. 程式人生 > 程式設計 >Node與Python 雙向通訊的實現程式碼

Node與Python 雙向通訊的實現程式碼

目錄
  • 程序通訊
  • 程序雙向通訊
  • 存在問題
  • 總結

第三方資料供應商把資料和封裝到一起,只能通過呼叫 Python方法來實現資料查詢,如果可以通過Node 簡單封裝下實現 Python 方法呼叫可以快速上線並節省開發成本。

最簡單粗暴的通訊方式是 Node呼叫一下 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,監聽埠,這些手段可以翻譯成同步阻塞任務,同步非阻塞任務,其中代價最小的就是同步非阻塞任務,然後可以想到 的 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)CHNynl # 同步非阻塞
        data = ''
        for fileno,event in events:
            data += sys.stdin.readline() # 通過標準輸入獲取資料
            if data == 'CHNynl
' 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雙向通訊內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!