programing tip

node.js와 Python 결합

itbloger 2020. 7. 10. 08:07
반응형

node.js와 Python 결합


Node.js는 웹 프로젝트와 완벽하게 일치하지만 Python을 선호하는 계산 작업은 거의 없습니다. 우리는 또한 이미 파이썬 코드를 가지고 있습니다. 우리는 속도에 대해 매우 염려합니다. node.js에서 파이썬 "작업자"를 비동기 비 차단 방식으로 호출하는 가장 우아한 방법은 무엇입니까?


node.js와 Python 서버 간의 통신을 위해 두 프로세스가 동일한 서버에서 실행되고 그렇지 않으면 TCP / IP 소켓에서 Unix 소켓을 사용합니다. 마샬링 프로토콜의 경우 JSON 또는 프로토콜 버퍼를 사용 합니다. 스레드 파이썬이 병목 현상으로 나타나면 Twisted Python 사용을 고려하십시오 . 이는 node.js와 동일한 이벤트 기반 동시성을 제공합니다.

모험심이 느껴지면 clojure ( clojurescript , clojure-py )를 배우 면 Java, JavaScript (node.js 포함), CLR 및 Python의 기존 코드와 실행되고 상호 작용하는 동일한 언어를 얻을 수 있습니다. 클로저 데이터 구조를 사용하여 탁월한 마샬링 프로토콜을 얻을 수 있습니다.


이것은 zeroMQ가 적합한 시나리오처럼 들립니다. TCP 또는 Unix 소켓을 사용하는 것과 유사한 메시징 프레임 워크이지만 훨씬 강력합니다 ( http://zguide.zeromq.org/py:all )

zeroMQ를 사용하여 잘 작동하는 RPC 프레임 워크를 제공하는 라이브러리가 있습니다. 이를 zeroRPC ( http://www.zerorpc.io/ ) 라고 합니다. 여보세요 세계입니다.

파이썬 "Hello x"서버 :

import zerorpc

class HelloRPC(object):
    '''pass the method a name, it replies "Hello name!"'''
    def hello(self, name):
        return "Hello, {0}!".format(name)

def main():
    s = zerorpc.Server(HelloRPC())
    s.bind("tcp://*:4242")
    s.run()

if __name__ == "__main__" : main()

그리고 node.js 클라이언트 :

var zerorpc = require("zerorpc");

var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
//calls the method on the python object
client.invoke("hello", "World", function(error, reply, streaming) {
    if(error){
        console.log("ERROR: ", error);
    }
    console.log(reply);
});

또는 그 반대의 node.js 서버 :

var zerorpc = require("zerorpc");

var server = new zerorpc.Server({
    hello: function(name, reply) {
        reply(null, "Hello, " + name, false);
    }
});

server.bind("tcp://0.0.0.0:4242");

그리고 파이썬 클라이언트

import zerorpc, sys

c = zerorpc.Client()
c.connect("tcp://127.0.0.1:4242")
name = sys.argv[1] if len(sys.argv) > 1 else "dude"
print c.hello(name)

Python 작업자를 별도의 프로세스 (장기 실행 서버 유형 프로세스 또는 요청시 생성 된 자식)로 준비하면 노드와의 통신은 node.js 측에서 비동기식이됩니다. UNIX / TCP 소켓과 stdin / out / err 통신은 본질적으로 노드에서 비동기입니다.


Apache Thrift http://thrift.apache.org/ 도 고려하고 있습니다.

여러 프로그래밍 언어를 연결할 수 있으며 매우 효율적이며 비동기 또는 동기화 호출을 지원합니다. 여기에 전체 기능을 참조하십시오 http://thrift.apache.org/docs/features/

다국어는 향후 계획에 유용 할 수 있습니다. 예를 들어 나중에 C ++에서 계산 작업의 일부를 수행하려는 경우 Thrift를 사용하여 믹스에 추가하는 것이 매우 쉽습니다.


I've had a lot of success using thoonk.js along with thoonk.py. Thoonk leverages Redis (in-memory key-value store) to give you feed (think publish/subscribe), queue and job patterns for communication.

Why is this better than unix sockets or direct tcp sockets? Overall performance may be decreased a little, however Thoonk provides a really simple API that simplifies having to manually deal with a socket. Thoonk also helps make it really trivial to implement a distributed computing model that allows you to scale your python workers to increase performance, since you just spin up new instances of your python workers and connect them to the same redis server.


I'd recommend using some work queue using, for example, the excellent Gearman, which will provide you with a great way to dispatch background jobs, and asynchronously get their result once they're processed.

The advantage of this, used heavily at Digg (among many others) is that it provides a strong, scalable and robust way to make workers in any language to speak with clients in any language.


Update 2019

There are several ways to achieve this and here is the list in increasing order of complexity

  1. Python Shell, you will write streams to the python console and it will write back to you
  2. Redis Pub Sub, you can have a channel listening in Python while your node js publisher pushes data
  3. Websocket connection where Node acts as the client and Python acts as the server or vice-versa
  4. API connection with Express/Flask/Tornado etc working separately with an API endpoint exposed for the other to query

Approach 1 Python Shell Simplest approach

source.js file

const ps = require('python-shell')
// very important to add -u option since our python script runs infinitely
var options = {
    pythonPath: '/Users/zup/.local/share/virtualenvs/python_shell_test-TJN5lQez/bin/python',
    pythonOptions: ['-u'], // get print results in real-time
    // make sure you use an absolute path for scriptPath
    scriptPath: "./subscriber/",
    // args: ['value1', 'value2', 'value3'],
    mode: 'json'
};

const shell = new ps.PythonShell("destination.py", options);

function generateArray() {
    const list = []
    for (let i = 0; i < 1000; i++) {
        list.push(Math.random() * 1000)
    }
    return list
}

setInterval(() => {
    shell.send(generateArray())
}, 1000);

shell.on("message", message => {
    console.log(message);
})

destination.py file

import datetime
import sys
import time
import numpy
import talib
import timeit
import json
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

size = 1000
p = 100
o = numpy.random.random(size)
h = numpy.random.random(size)
l = numpy.random.random(size)
c = numpy.random.random(size)
v = numpy.random.random(size)

def get_indicators(values):
    # Return the RSI of the values sent from node.js
    numpy_values = numpy.array(values, dtype=numpy.double) 
    return talib.func.RSI(numpy_values, 14)

for line in sys.stdin:
    l = json.loads(line)
    print(get_indicators(l))
    # Without this step the output may not be immediately available in node
    sys.stdout.flush()

Notes: Make a folder called subscriber which is at the same level as source.js file and put destination.py inside it. Dont forget to change your virtualenv environment

참고URL : https://stackoverflow.com/questions/10775351/combining-node-js-and-python

반응형