본문 바로가기

백엔드

[Node.js] Child Process를 통해 Node.js에서 파이썬 스크립트 파일 구동하기

개요

PyTorch로 훈련시킨 EfficientNet 딥러닝 모델을 Express.js 프레임워크에서 구동시키기 위해 Node.js 상에서 파이썬 파일을 구동할 필요가  생겼다.

 

 

코드

아래 Express.js로 작성된 서버에서 POST 요청을 통해 사진 하나가 서버의 upload 디렉토리로 업로드 된다. 이후 'child_process'의 spawn을 통해 python 파일을 수행하게 된다. 

 

 

Node.js 파일

const express = require('express');
const app = express();
const multer = require('multer');
const path = require('path');
const uploader = multer({
    storage: multer.diskStorage({
        destination(req,file,cb){
            cb(null, 'upload/');
        },
        filename(req,file,cb){
            const ext = path.extname(file.originalname);
            cb(null, 'file_'+Date.now()+ext);
        }
    }),
    limits: {fileSize: 5*1024*1024},
});
const spawn = require('child_process').spawn


app.post('/', uploader.single('image'),async(req,res)=>{
    //spawn으로 파이썬 스크립트 실행
    //실행할 파일(app.py)와  매개변수로 저장된 파일명을 전달
    const net = spawn('python',['app.py',req.file.filename]);
    
    //파이썬 파일 수행 결과를 받아온다
    net.stdout.on('data', function(data) { 
        console.log(data);
        console.log(data.toString());
        if(data.toString() == 'nsfw')
            res.status(200).send('nsfw')
        else
            res.status(200).send('sfw')
    })
})

app.listen(3000, () => {
    console.log('listening on *:3000');
  });

 

 

app.py 파일

 받아온 파일 명을 불러와서 이미지에 대한 딥러닝 예측을 수행하고 결과를 프린트한다. 프린트 내용은 Node.js 파일에서 받을 수 있다. 해당 과정에서 중요한 점 하나는 print 시에 개행을 방지하기 위해 print("프린트 내용",end='')라고 작성해주어야 한다. 그렇지 않으면 Node.js 쪽에서 결과를 받을 때 개행 버퍼 값이 넘어간다.

import torch
from efficientnet_pytorch import EfficientNet
from torchvision import transforms
from PIL import Image
import time
import sys #acquire parameters

# 코드 생략...

def predict(path):
    img = tfms(Image.open(upload_path+path)).unsqueeze(0)
    with torch.no_grad():
        outputs = model(img)
        prob = torch.softmax(outputs,1)
    #for idx in torch.topk(outputs,k=2).indices.squeeze(0).tolist():
    result = 'nsfw' if torch.softmax(outputs,1)[0,0].item() > 0.5 else 'sfw'
    print(result,end='')
    sys.stdout.flush()

# import sys를 활용하여 매개변수를 받아온다.
if __name__ == '__main__':
    predict(sys.argv[1])

 

 

Child Process

Node.js는 Child Process를 생성할 수 있다. 자식 프로세스들은 stdin, stdout, stderr를 항상 가지며 부모는 비동기 방식으로 자식 프로세스의 해당 데이터를 스트리밍할 수 있다.

 

위 과정에서 주로 spawn과 exec을 사용한다. 둘 다 자식 프로세스로 작업을 한다는 점은 공통점이다. 하지만 'spawn'의 경우 스트림을, 'exec'의 경우 버퍼를 반환한다. 또한, 'spawn'은 비동기로 실행하고 결과도 비동기이다. 반대로 'exce'은 동기로 실행하며 결과는 비동기로 받는다.

 

보통 자식 프로세스에서 큰 바이너리 데이터를 받는 경우 'spawn', 200K 이하의 버퍼를 받는 경우 'exec'을 사용한다. 'spawn'은 지속적인 통신이 가능하고, 'exec'은 함수와 비슷하다고 볼 수 있다.

 

Node.js Spawn vs. Execute

In an online training video I am watching to learn Node, the narrator says that "spawn is better for longer processes involving large amounts of data, whereas execute is better for short bits of da...

stackoverflow.com

 

 

How to Optimize CPU-Intensive Work in Node.js

The purpose of this post is to familiarize the reader with launching external processes in Node. There is a GitHub readme with starter-code…

medium.com

 

 

Child Process Node.js v0.8.15 Manual & Documentation

Child Process# Stability: 3 - Stable Node provides a tri-directional popen(3) facility through the child_process module. It is possible to stream data through a child's stdin, stdout, and stderr in a fully non-blocking way. To create a child process use re

nodejs.sideeffect.kr