Menggabungkan node.js dan Python

127

Node.js adalah pasangan yang sempurna untuk proyek web kami, tetapi ada beberapa tugas komputasi yang kami inginkan untuk Python. Kami juga sudah memiliki kode Python untuk mereka. Kami sangat memperhatikan kecepatan, apa cara paling elegan untuk memanggil "pekerja" Python dari node.js dengan cara non-pemblokiran yang tidak sinkron?

Cartesius00
sumber
3
Hai, dapatkah Anda berbagi dengan kami apa yang Anda pilih dan bagaimana hasilnya bagi Anda? Ada perpustakaan di Python yang kita semua suka gunakan sambil menjaga opsi kinerja dan non-blocking. Terima kasih
Maziyar
Bagaimana dengan hanya menelurkan / bercabang proses dan berkomunikasi melalui sistem IO, seperti yang ini sarankan: sohamkamani.com/blog/2015/08/21/python-nodejs-comm ?
lkahtz
Ada perpustakaan bridging baru bernama PyNode yang memungkinkan Anda untuk memanggil Python dan mendapatkan kembali jenis JS. Ini ditunjukkan di sini thecodinginterface.com/blog/…
SciGuyMcQ

Jawaban:

86

Untuk komunikasi antara node.js dan server Python, saya akan menggunakan soket Unix jika kedua proses berjalan pada server yang sama dan soket TCP / IP sebaliknya. Untuk protokol marshaling saya akan mengambil JSON atau buffer protokol . Jika Python berulir muncul menjadi hambatan, pertimbangkan untuk menggunakan Twisted Python , yang menyediakan konkurensi yang didorong oleh peristiwa yang sama seperti yang dilakukan node.js.

Jika Anda merasa ingin bertualang, pelajari clojure ( clojurescript , clojure-py ) dan Anda akan mendapatkan bahasa yang sama yang berjalan dan berinteroperasi dengan kode yang ada di Java, JavaScript (termasuk node.js), CLR dan Python. Dan Anda mendapatkan protokol marshalling yang luar biasa hanya dengan menggunakan struktur data clojure.

Aleš Kotnik
sumber
2
Apakah Anda tahu jika sesuatu seperti ini akan bekerja pada Heroku, yang memiliki sistem file fana?
cm2
119

Ini terdengar seperti skenario di mana zeroMQ akan cocok. Ini adalah kerangka kerja perpesanan yang mirip dengan menggunakan soket TCP atau Unix, tetapi jauh lebih kuat ( http://zguide.zeromq.org/py:all )

Ada perpustakaan yang menggunakan zeroMQ untuk menyediakan kerangka kerja RPC yang bekerja dengan cukup baik. Ini disebut zeroRPC ( http://www.zerorpc.io/ ). Inilah dunia halo.

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

Dan klien 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);
});

Atau sebaliknya, server 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");

Dan klien 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)
djheru
sumber
4
Bisakah zerorpc menangani beberapa status jika ada beberapa sesi klien?
user1027169
Jawaban yang bagus, contoh contoh, penjelasan yang banyak dan apa yang saya cari. TY. +1
Gaurav Gandhi
1
jika Anda baru seperti saya, instal dependensi yang mereka sebutkan di sini - ianhinsdale.com/code/2013/12/08/…
Darpan
Terima kasih banyak untuk ini!
Gezim
1
Demo halo dunia yang bagus! Solusi serupa lainnya di bawah ini menggunakan Rabbitmq. medium.com/@HolmesLaurence/…
teng
7

Jika Anda mengatur agar pekerja Python Anda dalam proses yang terpisah (baik proses tipe server yang berjalan lama atau anak yang dilahirkan atas permintaan), komunikasi Anda dengannya akan tidak sinkron di sisi node.js. Soket UNIX / TCP dan komunikasi stdin / out / err secara inheren async dalam node.

lanzz
sumber
6

Saya juga akan mempertimbangkan Apache Thrift http://thrift.apache.org/

Ini dapat menjembatani antara beberapa bahasa pemrograman, sangat efisien dan memiliki dukungan untuk panggilan sinkronisasi atau async. Lihat fitur lengkap di sini http://thrift.apache.org/docs/features/

Multi bahasa dapat berguna untuk rencana masa depan, misalnya jika Anda kemudian ingin melakukan bagian dari tugas komputasi dalam C ++, sangat mudah untuk menambahkannya ke dalam campuran menggunakan Thrift.

Iftah
sumber
5

Saya sudah banyak sukses menggunakan thoonk.js bersama dengan thoonk.py . Thoonk memanfaatkan Redis (in-memory key-value store) untuk memberi Anda umpan (pikirkan publikasi / berlangganan), antrian dan pola pekerjaan untuk komunikasi.

Mengapa ini lebih baik daripada soket unix atau soket tcp langsung? Kinerja keseluruhan mungkin sedikit menurun, namun Thoonk menyediakan API yang sangat sederhana yang menyederhanakan harus berurusan dengan soket secara manual. Thoonk juga membantu menjadikannya sangat sepele untuk mengimplementasikan model komputasi terdistribusi yang memungkinkan Anda untuk meningkatkan skala pekerja python Anda untuk meningkatkan kinerja, karena Anda hanya memutar-mutar instance baru dari pekerja python Anda dan menghubungkannya ke server redis yang sama.

Doug McCall
sumber
3

Saya akan merekomendasikan menggunakan beberapa antrian kerja menggunakan, misalnya, Gearman yang sangat baik , yang akan memberi Anda cara yang hebat untuk mengirimkan pekerjaan latar belakang, dan secara tidak sinkron mendapatkan hasilnya setelah diproses.

Keuntungan dari ini, banyak digunakan di Digg (di antara banyak lainnya) adalah bahwa ia menyediakan cara yang kuat, terukur dan kuat untuk membuat pekerja dalam bahasa apa pun untuk berbicara dengan klien dalam bahasa apa pun.

Pierre
sumber
1

Perbarui 2019

Ada beberapa cara untuk mencapai hal ini dan berikut adalah daftar dengan urutan kompleksitas yang meningkat

  1. Python Shell, Anda akan menulis stream ke konsol python dan itu akan menulis kembali kepada Anda
  2. Redis Pub Sub, Anda dapat memiliki saluran mendengarkan dengan Python sementara penerbit node Anda mendorong data
  3. Koneksi Websocket di mana Node bertindak sebagai klien dan Python bertindak sebagai server atau sebaliknya
  4. Koneksi API dengan Express / Flask / Tornado dll. Bekerja secara terpisah dengan titik akhir API yang diekspos untuk yang lain untuk di-query

Pendekatan 1 Pendekatan Python Shell Sederhana

file 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);
})

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

Catatan : Buat folder yang disebut pelanggan yang setingkat dengan file source.js dan masukkan destination.py di dalamnya. Jangan lupa untuk mengubah lingkungan virtualenv Anda

PirateApp
sumber