Node.js는 웹 프로젝트와 완벽하게 일치하지만 Python을 선호하는 계산 작업은 거의 없습니다. 우리는 또한 이미 파이썬 코드를 가지고 있습니다. 우리는 속도에 대해 매우 염려합니다. node.js에서 파이썬 "작업자"를 비동기 비 차단 방식으로 호출하는 가장 우아한 방법은 무엇입니까?
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)
Apache Thrift http://thrift.apache.org/ 도 고려하고 있습니다.
여러 프로그래밍 언어를 연결할 수 있으며 매우 효율적이며 비동기 또는 동기화 호출을 지원합니다. 여기에 전체 기능을 참조하십시오 http://thrift.apache.org/docs/features/
다국어는 향후 계획에 유용 할 수 있습니다. 예를 들어 나중에 C ++에서 계산 작업의 일부를 수행하려는 경우 Thrift를 사용하여 믹스에 추가하는 것이 매우 쉽습니다.
thoonk.js 와 thoonk.py 를 사용하여 많은 성공을 거두었 습니다 . Thoonk는 Redis (메모리 내 키-값 저장소)를 활용하여 통신을위한 피드 (게시 / 구독), 대기열 및 작업 패턴을 제공합니다.
이것이 유닉스 소켓이나 직접 TCP 소켓보다 나은 이유는 무엇입니까? 전반적인 성능은 약간 떨어질 수 있지만 Thoonk은 소켓을 수동으로 처리 해야하는 것을 단순화하는 매우 간단한 API를 제공합니다. Thoonk은 또한 파이썬 작업자의 새 인스턴스를 스핀 업하고 동일한 redis 서버에 연결하기 때문에 성능을 향상시키기 위해 파이썬 작업자를 확장 할 수있는 분산 컴퓨팅 모델을 구현하는 것이 매우 간단합니다.
2019 업데이트
이를 달성하는 방법에는 여러 가지가 있으며 여기에는 복잡성이 증가하는 목록이 있습니다.
접근법 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 환경을 변경하는 것을 잊지 마십시오