结合node.js和Python

y0u0uwnf  于 2023-06-29  发布在  Node.js
关注(0)|答案(8)|浏览(129)

Node.js非常适合我们的Web项目,但我们更喜欢Python的计算任务很少。我们也已经有了一个Python代码。我们非常关心速度,如何以异步非阻塞的方式从node.js调用Python“worker”的最优雅的方式是什么?

0qx6xfy6

0qx6xfy61#

这听起来像是一个适合zeroMQ的场景。它是一个类似于使用TCP或Unix套接字的消息传递框架,但它更健壮(http://zguide.zeromq.org/py:all
有一个库使用zeroMQ来提供一个运行良好的RPC框架。它被称为zeroRPC(http://www.zerorpc.io/)。这是Hello World。
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)
uemypmqf

uemypmqf2#

对于node.js和Python服务器之间的通信,如果两个进程都运行在同一个服务器上,我会使用Unix套接字,否则使用TCP/IP套接字。对于封送协议,我会采用JSON或protocol buffer。如果线程化Python成为瓶颈,请考虑使用Twisted Python,它提供了与node.js相同的事件驱动并发性。
如果你喜欢冒险,学习clojureclojurescriptclojure-py),你将获得与Java,JavaScript(包括node.js),CLR和Python上现有代码运行和互操作的相同语言。通过简单地使用clojure数据结构,您可以获得极好的编组协议。

mftmpeh8

mftmpeh83#

如果你安排你的Python worker在一个单独的进程中(无论是长时间运行的服务器类型的进程还是按需产生的子进程),你与它的通信在node.js端将是异步的。UNIX/TCP套接字和stdin/out/err通信在节点中是固有异步的。

i34xakig

i34xakig4#

我在使用thoonk.js沿着thoonk.py时取得了很多成功。Thoonk利用Redis(内存中的键值存储)为您提供feed(想想发布/订阅),队列和作业模式进行通信。
为什么这比unix套接字或直接tcp套接字好?整体性能可能会有所下降,但Thoonk提供了一个非常简单的API,简化了手动处理套接字的工作。Thoonk还有助于实现一个分布式计算模型,允许你扩展你的python工作者来提高性能,因为你只需要启动你的python工作者的新示例,并将它们连接到同一个redis服务器。

js81xvg6

js81xvg65#

Apache Thrift http://thrift.apache.org/
它可以在几种编程语言之间建立桥梁,效率很高,并且支持异步或同步调用。在此查看完整功能http://thrift.apache.org/docs/features/
多语言对未来的计划很有用,例如,如果你以后想用C++完成部分计算任务,很容易使用Thrift将其添加到混合中。

dtcbnfnu

dtcbnfnu6#

我建议使用一些工作队列,例如,使用优秀的Gearman,它将为您提供一种很好的方式来分派后台作业,并在处理后异步获取结果。
Digg(以及其他许多公司)大量使用的这种方法的优点是,它提供了一种强大的,可扩展的和健壮的方式,使任何语言的工人与任何语言的客户交谈。

9cbw7uwe

9cbw7uwe7#

2019年更新

有几种方法可以实现这一点,这里是复杂性增加的列表

  1. PythonShell,您将向python控制台写入流,它将向您回写
  2. Redis Pub Sub,你可以在你的节点js publisher推送数据的时候,让一个通道在Python中监听
  3. WebSocket连接,其中Node充当客户端,Python充当服务器,反之亦然
    1.与Express/Flask/Tornado等的API连接,单独使用暴露的API端点进行查询

方法1 Python Shell最简单的方法
源.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);
})

目标.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()

注意事项:创建一个subscriber文件夹,与source.js文件同级,将www.example.comdestination.py放入其中,注意修改virtualenv环境

hec6srdp

hec6srdp8#

更新2023
我创建了一个允许您将Python与NodeJS一起使用的库
JavaScript库:https://github.com/7HR4IZ3/js_bridge
Python库:https://github.com/7HR4IZ3/py_bridge
JavaScript示例

const { python } = require("js_bridge");
const py = python();

async function myPythonFunction() {
   let math = await py.import("math");
    let result = await math.sqrt(16);
    console.log(result);
}

myPythonFunction();

Python示例

from py_bridge import nodejs

node1 = nodejs(port=7000)
node2 = nodejs(port-7001)

node1.setup(name="my_node")
node2.setup(name="nodejs2") # name parameter is for imports

node1.console.log("Hello from node1")
node2.console.log("Hello from node2")

fs = node1.require("fs") # also supports 'from my_node import fs'
print(fs.readSync("./mytext.txt"))

相关问题