结合使用node.js和Python


127

Node.js非常适合我们的Web项目,但是很少有需要Python的计算任务。我们已经为他们准备了Python代码。我们非常关心速度,如何以异步非阻塞方式从node.js调用Python“工作者”的最优雅方法是什么?


3
嗨,您能与我们分享您选择了什么以及如何为您服务吗?我们所有人都喜欢使用Python中的库,同时保留性能和非阻塞选项。谢谢
Maziyar

简单地生成/派生一个进程并通过系统IO进行通信,就像这样建议的那样:sohamkamani.com/blog/2015/08/21/python-nodejs-comm呢?
lkahtz

有一个名为PyNode的新桥接库,允许您调用Python并返回JS类型。这里展示了thecodinginterface.com/blog/…–
SciGuyMcQ

Answers:


86

对于node.js和Python服务器之间的通信,如果两个进程都在同一服务器上运行,则我将使用Unix套接字,否则将使用TCP / IP套接字。对于封送处理协议,我将使用JSON或协议缓冲区。如果线程化Python成为瓶颈,请考虑使用Twisted Python,它提供与node.js相同的事件驱动的并发性。

如果您喜欢冒险,请学习clojureclojurescriptclojure-py),您将获得与Java,JavaScript(包括node.js),CLR和Python上的现有代码可运行并互操作的相同语言。通过使用clojure数据结构,您将获得出色的编组协议。


2
您知道这样的事情是否可以在具有临时文件系统的Heroku上运行吗?
cm2

119

这听起来像一个零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)

4
如果有多个客户端会话,zerorpc可以处理多个状态吗?
2013年

好的答案,示例示例,丰富的解释以及我想要的东西。TY。+1
Gaurav Gandhi

1
如果你是新的我一样,安装他们的方式在这里提到的依赖关系- ianhinsdale.com/code/2013/12/08/...
Darpan

非常感谢!
Gezim '17

1
大家好,世界演示!下面另一个使用Rabbitmq的类似解决方案。medium.com/@HolmesLaurence/...
10克

7

如果您安排将Python工作进程放在单独的进程中(长时间运行的服务器类型进程或按需生成的子进程),则与之进行的通信在node.js端将是异步的。UNIX / TCP套接字和stdin / out / err通信本身在节点中是异步的。


6

我也会考虑Apache Thrift http://thrift.apache.org/

它可以在几种编程语言之间架起桥梁,非常高效,并支持异步或同步调用。在此处查看完整功能http://thrift.apache.org/docs/features/

多语言可能对将来的计划很有用,例如,如果您以后想要在C ++中完成部分计算任务,则可以很容易地使用Thrift将其添加到混合中。


5

使用thoonk.jsthoonk.py取得了很多成功。Thoonk利用Redis(内存中的键值存储)为您提供供稿(如发布/订阅),队列和作业模式进行通信。

为什么这比unix套接字或直接tcp套接字更好?总体性能可能会有所下降,但是Thoonk提供了一个非常简单的API,该API简化了手动处理套接字的过程。Thoonk还可帮助您轻松实现一个分布式计算模型,该模型可让您扩展python worker来提高性能,因为您只是启动了python worker的新实例并将它们连接到同一Redis服务器。


3

我建议使用一些工作队列,例如使用出色的Gearman,它将为您提供一种很好的方式来调度后台作业,并在处理后异步获取其结果。

Digg(在许多其他公司中)经常使用的优点是,它提供了一种强大,可扩展和强大的方法,使任何语言的工作人员都能与任何语言的客户进行交谈。


1

更新2019

有几种方法可以做到这一点,以下是按复杂度从高到低排列的清单

  1. Python Shell,您将流写入python控制台,它将回写给您
  2. Redis Pub Sub,当节点js发布者推送数据时,您可以使用Python监听频道
  3. Websocket连接,其中Node充当客户端,Python充当服务器,反之亦然
  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文件位于同一级别,并将destination.py放入其中。不要忘记更改您的virtualenv环境

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.