node.jsとPythonを組み合わせる


127

Node.jsは私たちのWebプロジェクトに完全に一致しますが、Pythonを好む計算タスクはほとんどありません。また、Pythonコードも既に用意されています。私たちは速度に非常に関心があります。非同期の非ブロッキング方法でnode.jsからPythonの「ワーカー」を呼び出す最もエレガントな方法は何ですか?


3
こんにちは、何を選びましたか、それがどのように機能したかを教えてください。Pythonには、パフォーマンスと非ブロッキングのオプションを維持しながら、私たち全員が使用したいライブラリがあります。ありがとう
Maziyar 2013年

次のように、単純にプロセスを生成/フォークし、システムIOを介して通信することについてはどうですか?sohamkamani.com/blog/2015/08/21/python-nodejs-comm
lkahtz 2017

Pythonを呼び出してJSタイプを返すことができるPyNodeという名前の新しいブリッジライブラリがあります。それはここで実証されていますthecodinginterface.com/blog/...
SciGuyMcQ

回答:


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

これは、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");

そして、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は複数の状態を処理できますか?
user1027169 2013年

良い答え、サンプルの例、豊富な説明、そして私が探していたもの。TY。+1
Gaurav Gandhi 2016

1
あなたは私のような新しいしている場合、彼らは道ここに言及した依存関係をインストール- ianhinsdale.com/code/2013/12/08/...を
Darpan

どうもありがとうございました!
Gezim

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(インメモリKey-Valueストア)を利用して、フィード(パブリッシュ/サブスクライブを考える)、キュー、および通信のジョブパターンを提供します。

なぜこれがUNIXソケットや直接TCPソケットよりも優れているのですか?全体的なパフォーマンスは少し低下する可能性がありますが、Thoonkはソケットを手動で処理する必要があることを簡素化する本当にシンプルなAPIを提供します。Thoonkは、Pythonワーカーの新しいインスタンスを起動して同じRedisサーバーに接続するだけなので、Pythonワーカーをスケーリングしてパフォーマンスを向上できる分散コンピューティングモデルを実装することを非常に簡単にするのにも役立ちます。


3

たとえば、優れたGearmanを使用してワークキューを使用することをお勧めします。これにより、バックグラウンドジョブをディスパッチし、処理後に非同期で結果を取得できます。

Diggで頻繁に使用されているこの利点は、他の多くの言語の中でも特に、Diggが強力でスケーラブルで堅牢な方法を提供して、任意の言語のワーカーが任意の言語のクライアントと話すことができることです。


1

2019年更新

これを実現するにはいくつかの方法があります。ここに複雑さの昇順のリストを示します

  1. Python Shell、ストリームをpythonコンソールに書き込み、それを返信します
  2. Redis Pub Sub、ノードのjsパブリッシャーがデータをプッシュしている間、チャンネルをPythonでリッスンできます
  3. ノードがクライアントとして機能し、Pythonがサーバーとして機能する、またはその逆のWebsocket接続
  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ファイルと同じレベルにあるsubscriberという名前のフォルダーを作成し、その中にdestination.pyを置きます。virtualenv環境を変更することを忘れないでください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.