[python] 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를 사용하여 믹스에 추가하는 것이 매우 쉽습니다.


답변

thoonk.jsthoonk.py 를 사용하여 많은 성공을 거두었 습니다 . Thoonk는 Redis (메모리 내 키-값 저장소)를 활용하여 통신을위한 피드 (게시 / 구독), 대기열 및 작업 패턴을 제공합니다.

이것이 유닉스 소켓이나 직접 TCP 소켓보다 나은 이유는 무엇입니까? 전반적인 성능은 약간 떨어질 수 있지만 Thoonk은 소켓을 수동으로 처리 해야하는 것을 단순화하는 매우 간단한 API를 제공합니다. Thoonk은 또한 파이썬 작업자의 새 인스턴스를 스핀 업하고 동일한 redis 서버에 연결하기 때문에 성능을 향상시키기 위해 파이썬 작업자를 확장 할 수있는 분산 컴퓨팅 모델을 구현하는 것이 매우 간단합니다.


답변

백그라운드 작업을 디스패치하고 처리가 끝나면 비동기식으로 결과를 얻을 수 있는 훌륭한 Gearman 과 같은 작업 대기열을 사용하는 것이 좋습니다 .

Digg에서 많은 사람들이 사용하는 이점은 모든 언어의 작업자가 모든 언어의 고객과 대화 할 수있는 강력하고 확장 가능하며 강력한 방법을 제공한다는 것입니다.


답변

2019 업데이트

이를 달성하는 방법에는 여러 가지가 있으며 여기에는 복잡성이 증가하는 목록이 있습니다.

  1. Python Shell, python 콘솔에 스트림을 작성하고 다시 작성합니다.
  2. Redis Pub Sub, Node js 게시자가 데이터를 푸시하는 동안 Python에서 채널 청취를 할 수 있습니다
  3. Node가 클라이언트로 작동하고 Python이 서버로 작동하거나 그 반대로 작동하는 Websocket 연결
  4. Express / Flask / Tornado 등과의 API 연결은 다른 쪽이 쿼리에 노출 된 API 엔드 포인트와 별도로 작동

접근법 1 Python Shell 가장 간단한 접근법

source.js 파일

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 파일

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()

참고 : source.js 파일과 동일한 수준에있는 subscriber라는 폴더를 만들고 destination.py를 그 안에 넣으십시오. virtualenv 환경을 변경하는 것을 잊지 마십시오