Kết hợp node.js và Python


127

Node.js là một kết hợp hoàn hảo cho dự án web của chúng tôi, nhưng có một số nhiệm vụ tính toán mà chúng tôi thích Python hơn. Chúng tôi cũng đã có một mã Python cho họ. Chúng tôi rất quan tâm đến tốc độ, cách thức thanh lịch nhất để gọi một "worker" Python từ node.js theo cách không chặn không đồng bộ là gì?


3
Xin chào, bạn có thể chia sẻ với chúng tôi những gì bạn đã chọn và cách nó phù hợp với bạn không? Có những thư viện trong Python mà tất cả chúng ta đều thích sử dụng trong khi vẫn giữ hiệu suất và các tùy chọn không chặn. Cảm ơn
Maziyar

Điều gì về việc đơn giản sinh ra / rẽ nhánh một quá trình và giao tiếp qua hệ thống IO, như thế này gợi ý: sohamkamani.com/blog/2015/08/21/python-nodejs-comm ?
lkahtz

Có một thư viện bắc cầu mới có tên PyNode cho phép bạn gọi Python và nhận các loại JS được trả về. Nó được trình diễn ở đây thecodinginterface.com/blog/ cường
SciGuyMcQ

Câu trả lời:


86

Để liên lạc giữa node.js và máy chủ Python, tôi sẽ sử dụng ổ cắm Unix nếu cả hai quá trình chạy trên cùng một máy chủ và ổ cắm TCP / IP khác. Đối với giao thức sắp xếp theo thứ tự, tôi sẽ lấy JSON hoặc bộ đệm giao thức . Nếu Python có luồng hiển thị là một nút cổ chai, hãy xem xét sử dụng Twisted Python , nó cung cấp sự tương tranh theo hướng sự kiện tương tự như node.js.

Nếu bạn cảm thấy thích phiêu lưu, hãy tìm hiểu clojure ( clojurescript , clojure-py ) và bạn sẽ có cùng ngôn ngữ chạy và tương tác với mã hiện có trên Java, JavaScript (bao gồm node.js), CLR và Python. Và bạn có được giao thức sắp xếp tuyệt vời chỉ bằng cách sử dụng các cấu trúc dữ liệu clojure.


2
Bạn có biết nếu một cái gì đó như thế này sẽ hoạt động trên Heroku, có hệ thống tập tin phù du?
cm2

119

Điều này nghe có vẻ như một kịch bản trong đó zeroMQ sẽ phù hợp. Đó là một khung nhắn tin tương tự như sử dụng các socket TCP hoặc Unix, nhưng nó mạnh mẽ hơn nhiều ( http://zguide.zeromq.org/py:all )

Có một thư viện sử dụng zeroMQ để cung cấp khung RPC hoạt động khá tốt. Nó được gọi là zeroRPC ( http://www.zerorpc.io/ ). Đây là thế giới xin chào.

Máy chủ Python "Xin chào 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()

Và ứng dụng khách 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);
});

Hoặc ngược lại, máy chủ 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");

Và khách hàng trăn

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 có thể xử lý nhiều trạng thái trong trường hợp có nhiều phiên khách không?
dùng1027169

Câu trả lời tốt, ví dụ mẫu, giải thích phong phú và những gì tôi đang tìm kiếm. TY. +1
Gaurav Gandhi

1
nếu bạn là người mới như tôi, hãy cài đặt các phụ thuộc mà họ đã đề cập ở đây - ianhinsdale.com/code/2013/12/08/NH
Darpan

Cảm ơn rất nhiều vì chuyện này!
Gezim

1
Xin chào thế giới demo! Một giải pháp tương tự khác dưới đây bằng Rabbitmq. Medium.com/@HolmesLaurence/ từ
teng

7

Nếu bạn sắp xếp để có nhân viên Python của mình trong một quy trình riêng (quy trình loại máy chủ chạy dài hoặc con sinh ra theo yêu cầu), giao tiếp của bạn với nó sẽ không đồng bộ ở phía node.js. Các socket UNIX / TCP và giao tiếp stdin / out / err vốn không đồng bộ trong nút.


6

Tôi cũng xem xét Apache Thrift http://thrift.apache.org/

Nó có thể kết nối giữa một số ngôn ngữ lập trình, có hiệu quả cao và có hỗ trợ cho các cuộc gọi không đồng bộ hoặc đồng bộ hóa. Xem các tính năng đầy đủ tại đây http://thrift.apache.org/docs/features/

Đa ngôn ngữ có thể hữu ích cho các kế hoạch trong tương lai, ví dụ nếu sau này bạn muốn thực hiện một phần của nhiệm vụ tính toán trong C ++, thật dễ dàng để thêm nó vào hỗn hợp bằng Thrift.


5

Tôi đã có rất nhiều thành công khi sử dụng thoonk.js cùng với thoonk.py . Thoonk tận dụng Redis (lưu trữ khóa-giá trị trong bộ nhớ) để cung cấp cho bạn nguồn cấp dữ liệu (nghĩ xuất bản / đăng ký), xếp hàng và các mẫu công việc để liên lạc.

Tại sao điều này tốt hơn so với ổ cắm unix hoặc ổ cắm tcp trực tiếp? Hiệu suất tổng thể có thể giảm đi một chút, tuy nhiên Thoonk cung cấp API thực sự đơn giản giúp đơn giản hóa việc phải tự xử lý ổ cắm. Thoonk cũng giúp thực hiện một mô hình điện toán phân tán cho phép bạn mở rộng quy mô nhân viên python của mình để tăng hiệu suất, vì bạn chỉ cần quay các phiên bản mới của nhân viên python và kết nối chúng với cùng một máy chủ redis.


3

Tôi khuyên bạn nên sử dụng một số hàng đợi công việc bằng cách sử dụng, ví dụ, Gearman xuất sắc , sẽ cung cấp cho bạn một cách tuyệt vời để gửi các công việc nền và nhận được kết quả của chúng một cách không đồng bộ khi chúng được xử lý.

Ưu điểm của việc này, được sử dụng rất nhiều tại Digg (trong số nhiều người khác) là nó cung cấp một cách mạnh mẽ, có thể mở rộng và mạnh mẽ để khiến người lao động bằng bất kỳ ngôn ngữ nào nói chuyện với khách hàng bằng bất kỳ ngôn ngữ nào.


1

Cập nhật 2019

Có một số cách để đạt được điều này và đây là danh sách theo thứ tự tăng dần về độ phức tạp

  1. Python Shell, bạn sẽ ghi luồng vào bảng điều khiển python và nó sẽ ghi lại cho bạn
  2. Redis Pub Sub, bạn có thể có một kênh nghe bằng Python trong khi nhà xuất bản nút js của bạn đẩy dữ liệu
  3. Kết nối Websocket nơi Node đóng vai trò là máy khách và Python hoạt động như máy chủ hoặc ngược lại
  4. Kết nối API với Express / Flask / Tornado, v.v ... hoạt động riêng với điểm cuối API được hiển thị cho người khác truy vấn

Cách tiếp cận 1 Python Shell Cách tiếp cận đơn giản nhất

tập tin 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);
})

tập tin Destination.txt

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

Lưu ý : Tạo một thư mục được gọi là thuê bao ở cùng cấp độ với tệp source.js và đặt Destination.txt bên trong nó. Đừng quên thay đổi môi trường virtualenv của bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.