You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Node.js异步函数与Python子进程协同运行?

问题原因分析

你的Python代码卡在proc.communicate()这一步,是因为该方法会阻塞等待子进程完全退出,但Node.js的app.js中fs.watchFile设置了persistent: true,会持续保持进程运行不退出,导致Python主线程被永久阻塞。用asyncio无效是因为subproc函数里的communicate()仍是同步阻塞操作,异步框架没发挥作用。

同时你的app.js存在两处语法错误:

  • 变量名错误:policies_file应该是text_file
  • 语法不闭合:fs.watchFile回调后缺少)和;,main函数定义缺少闭合}

解决方案一:修改Python代码,异步运行Node子进程不阻塞

通过asyncio.subprocess或线程实现异步处理子进程输出,让Python主线程可以同时执行GPIO代码。

基于asyncio的改进代码

import subprocess
import asyncio

async def read_node_output(proc):
    # 异步读取Node.js子进程的输出
    while True:
        line = await proc.stdout.readline()
        if not line:
            break
        print(f"Node.js输出: {line.decode('utf-8').strip()}")

async def start_node_proc():
    print("start subprocess")
    # 使用asyncio创建非阻塞子进程
    proc = await asyncio.create_subprocess_exec(
        "/usr/bin/node", "/home/user/git/corp/prudens-js/node/app.js",
        stdout=subprocess.PIPE
    )
    print("after start")
    # 启动异步读取输出的任务(不阻塞主线程)
    asyncio.create_task(read_node_output(proc))
    return proc

async def gpio_task():
    # 替换为你的实际GPIO逻辑
    print("GPIO任务启动")
    while True:
        await asyncio.sleep(2)
        print("GPIO操作执行中...")

async def main():
    print("start")
    # 同时启动Node子进程和GPIO任务
    await asyncio.gather(start_node_proc(), gpio_task())

asyncio.run(main())

基于线程的改进代码(适合不熟悉asyncio的场景)

import subprocess
import threading
import time

def read_node_output(proc):
    for line in iter(proc.stdout.readline, b''):
        print(f"Node.js输出: {line.decode('utf-8').strip()}")

def start_node_proc():
    print("start subprocess")
    proc = subprocess.Popen(
        ["/usr/bin/node", "/home/user/git/corp/prudens-js/node/app.js"],
        stdout=subprocess.PIPE
    )
    print("after start")
    # 用线程后台读取输出,不阻塞主线程
    threading.Thread(target=read_node_output, args=(proc,), daemon=True).start()
    return proc

def gpio_task():
    print("GPIO任务启动")
    while True:
        time.sleep(2)
        print("GPIO操作执行中...")

if __name__ == "__main__":
    print("start")
    proc = start_node_proc()
    # 用线程启动GPIO任务
    threading.Thread(target=gpio_task, daemon=True).start()
    # 主线程保持运行,按回车可终止所有进程
    input("按回车退出程序\n")
    proc.terminate()

解决方案二:改用Node.js调用Python GPIO代码

如果Node.js的文件监控逻辑已经成熟,可以让Node.js作为主进程,通过child_process模块调用Python的GPIO脚本,架构更符合Node.js的异步IO特性。

修复后的app.js

const fs = require('fs');
const { spawn } = require('child_process');

function main() {
    const text_file= '/home/user/git/corp/file.txt';
    // 修复变量名错误
    const text = fs.readFileSync(text_file, "utf8");
    console.log(text);    
    // 修复语法闭合问题
    fs.watchFile(text_file, {bigint: false, persistent: true, interval: 1}, (curr, prev) => { 
        const text= fs.readFileSync(text_file, "utf8");
        console.log(text);
    });

    // 启动Python GPIO子进程
    const gpioProc = spawn('python3', ['/home/user/git/corp/gpio_script.py']);
    // 监听Python输出
    gpioProc.stdout.on('data', (data) => {
        console.log(`Python GPIO输出: ${data.toString().trim()}`);
    });
    // 监听Python错误输出
    gpioProc.stderr.on('data', (data) => {
        console.error(`Python错误: ${data.toString().trim()}`);
    });
}

main();

Python GPIO脚本(gpio_script.py)

import time

print("Python GPIO进程启动")
while True:
    # 替换为你的实际GPIO控制代码
    print("执行GPIO操作")
    time.sleep(2)

方案对比

  • Python调用Node.js:适合已有成熟Python GPIO代码,不想大量改动的场景,需注意异步/线程处理避免阻塞。
  • Node.js调用Python:适合Node.js文件监控逻辑完善的场景,Node.js的异步特性更适配文件监控需求,架构更清晰。

内容的提问来源于stack exchange,提问作者verpas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:52:49