Node.js非常适合我们的Web项目,但是很少有需要Python的计算任务。我们已经为他们准备了Python代码。我们非常关心速度,如何以异步非阻塞方式从node.js调用Python“工作者”的最优雅方法是什么?
Node.js非常适合我们的Web项目,但是很少有需要Python的计算任务。我们已经为他们准备了Python代码。我们非常关心速度,如何以异步非阻塞方式从node.js调用Python“工作者”的最优雅方法是什么?
Answers:
对于node.js和Python服务器之间的通信,如果两个进程都在同一服务器上运行,则我将使用Unix套接字,否则将使用TCP / IP套接字。对于封送处理协议,我将使用JSON或协议缓冲区。如果线程化Python成为瓶颈,请考虑使用Twisted Python,它提供与node.js相同的事件驱动的并发性。
如果您喜欢冒险,请学习clojure(clojurescript,clojure-py),您将获得与Java,JavaScript(包括node.js),CLR和Python上的现有代码可运行并互操作的相同语言。通过使用clojure数据结构,您将获得出色的编组协议。
这听起来像一个零MQ非常合适的场景。这是一个消息传递框架,与使用TCP或Unix套接字类似,但功能更强大(http://zguide.zeromq.org/py:all)
有一个库使用zeroMQ提供了一个运行良好的RPC框架。它称为zeroRPC(http://www.zerorpc.io/)。这是你好世界。
Python“ 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");
和python客户端
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将其添加到混合中。
更新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文件位于同一级别,并将destination.py放入其中。不要忘记更改您的virtualenv环境