Поєднання node.js і Python


127

Node.js - це ідеальна відповідність для нашого веб-проекту, але є декілька обчислювальних завдань, для яких ми вважаємо за краще Python. Ми також маємо для них код Python. Нас дуже турбує швидкість, який найелегантніший спосіб викликати Python "робітника" з node.js асинхронним неблокувальним способом?


3
Привіт, ти міг би поділитися з нами, що ти обрав і як це склалося для тебе? У Python є бібліотеки, які ми всі любимо використовувати, зберігаючи продуктивність та не блокуючи параметри. Спасибі
Maziyar

Що з просто нерестувати / розщеплювати процес та спілкуватися через системний IO, як це пропонує: sohamkamani.com/blog/2015/08/21/python-nodejs-comm ?
lkahtz

Існує нова мостова бібліотека під назвою PyNode, яка дозволяє викликати Python і повернути типи JS. Це продемонстровано тут thecodinginterface.com/blog/…
SciGuyMcQ

Відповіді:


86

Для зв'язку між node.js та сервером Python, я би використовував сокети Unix, якщо обидва процеси працюють на одному сервері та TCP / IP-сокетами в іншому випадку. Для протоколу marshaling я б взяв JSON або буфер протоколу . Якщо потоковий Python виявляється вузьким місцем, розгляньте можливість використання Twisted Python , який забезпечує ту ж паралельність, керовану подіями, як і node.js.

Якщо ви відчуваєте пригоди, вивчіть clojure ( clojurescript , clojure-py ), і ви отримаєте ту саму мову, яка працює і взаємодіє з існуючим кодом на Java, JavaScript (включений node.js), CLR та Python. І ви отримуєте чудовий протокол маршалінгу, просто використовуючи структури даних clojure.


2
Чи знаєте ви, чи щось подібне буде працювати на Heroku, який має ефемерну файлову систему?
см2

119

Це звучить як сценарій, коли zeroMQ добре підійде. Це система обміну повідомленнями, схожа на використання сокетів 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");

І клієнт пітон

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 обробляти декілька станів у випадку, якщо є кілька сеансів клієнта?
користувач1027169

Хороша відповідь, приклади зразків, багато пояснень і що я шукав. TY. +1
Гаурав Ганді

1
якщо ви такі, як я, встановіть залежності, які вони тут згадували - ianhinsdale.com/code/2013/12/08/…
Darpan

Дякую за це!
Гезим

1
Приємний демо-привіт! Ще одне подібне рішення нижче, використовуючи Rabbitmq. medium.com/@HolmesLaurence / ...
Тен

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.js разом із thoonk.py . Thoonk використовує Redis (сховище ключових значень у пам'яті), щоб дати вам канал (думайте, публікуйте / підписуйтесь), черги та шаблони роботи для спілкування.

Чому це краще, ніж Unix розетки або прямі розетки tcp? Загальна продуктивність може трохи знизитися, проте Thoonk пропонує дійсно простий API, який спрощує необхідність вручну працювати з сокетом. Thoonk також допомагає зробити реально тривіальною реалізацію розподіленої обчислювальної моделі, яка дозволяє масштабувати ваших працівників python для підвищення продуктивності, оскільки ви просто розкручуєте нові екземпляри ваших пітонів і підключаєте їх до того ж сервера redis.


3

Я рекомендую використовувати деякі робочі черги, використовуючи, наприклад, відмінний Gearman , який надасть вам чудовий спосіб відправки фонових завдань та асинхронно отримати їх результат після їх обробки.

Перевага цього, що використовується в Digg (серед багатьох інших), полягає в тому, що він забезпечує сильний, масштабований і надійний спосіб змусити працівників будь-якою мовою спілкуватися з клієнтами будь-якою мовою.


1

Оновлення 2019 року

Існує декілька способів цього досягти, і ось цей список зростає в порядку складності

  1. Python Shell, ви запишете потоки на консоль python, і він запише вам назад
  2. Redis Pub Sub, ви можете прослуховувати канал у Python, поки ваш видавець вузлів js передає дані
  3. Підключення до Websocket, де Node виступає клієнтом, а Python - як сервер, або навпаки
  4. З'єднання API з Express / Flask / Tornado тощо працює окремо з кінцевою точкою 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);
})

файл target.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, і покладіть всередину target.py. Не забудьте змінити своє середовище virtualenv

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.