MessagePack-Aufruf von Ruby to Python-Methoden (oder Python to Ruby-Methoden) mithilfe von RPC

MessagePack - Eine Zusammenfassung des Aufrufs von Python-Methoden (oder umgekehrt) von Ruby mithilfe von RPC.

――Ich verwende hauptsächlich Ruby, aber ich möchte Berechnungsbibliotheken für Wissenschaft und Technologie wie Pythons Numpy und Matplotlib verwenden.

Wenn Sie es für solche Zwecke verwenden, können Sie möglicherweise die guten Punkte jeder Sprache nutzen.

Annahme

Was ist MessagePack-RPC?

Remote Procedure Call-Protokoll. Serialisieren Sie mit MessagePack.

Einzelheiten zu den technischen Daten finden Sie hier.

Es stehen Bibliotheken zur Verfügung, die MessagePack-RPC in verschiedenen Sprachen implementieren. Die folgenden beiden sind in Ruby und Python implementiert. Implementierungen verschiedener anderer Sprachen wurden veröffentlicht.

Übrigens scheint das Plug-In von neovim mit MessagePack-RPC implementiert werden zu können. Es gibt den Vorteil, dass das Plug-In in verschiedenen Sprachen implementiert werden kann, solange es den MessagePack-RPC-Spezifikationen entspricht.

Die Ruby-Version enthält fast keine Informationen in der README-Datei, selbst wenn Sie sich die offizielle Github-Seite ansehen. Hier finden Sie eine kurze Zusammenfassung der Verwendung.

Minimales Beispiel

Zunächst ein Beispiel für eine Ruby-Version eines Servers

server.rb



require 'msgpack/rpc'

class MyHandler
  def add(x,y)
    return x+y
  end
end

svr = MessagePack::RPC::Server.new
svr.listen('localhost', 18800, MyHandler.new)
svr.run

Beispiel für einen Ruby-Client

client.rb


require 'msgpack/rpc'
c = MessagePack::RPC::Client.new('localhost',18800)
result = c.call(:add, 1, 2)
puts result

Führen Sie wie folgt aus.

ruby server.rb &   #Server starten
ruby client.rb     #Das Ergebnis der Berechnung wird angezeigt

Es kann genauso in Python geschrieben werden.

server.py


import msgpackrpc

class MyHandler(object):

    def add(self, x, y):
        return x+y

svr = msgpackrpc.Server( MyHandler(), unpack_encoding='utf-8' )
svr.listen( msgpackrpc.Address('localhost',18800) )
svr.start()

client.py


import msgpackrpc

client = msgpackrpc.Client(msgpackrpc.Address("localhost", 18800), unpack_encoding='utf-8')
result = client.call('add', 1, 2)
print( result )

Wenn Sie einen Ruby-Server und einen Python-Client ausführen (oder umgekehrt), erhalten Sie natürlich genau das gleiche Ergebnis.

Im Fall von Python sollte beachtet werden, dass bei der Initialisierung des Clients oder Servers der Standardwert "unpack_encoding =" None "ist und die übertragenen Daten als Byte-Zeichenfolge interpretiert werden. Im obigen Beispiel gibt es kein Problem, da nur numerische Werte gesendet und empfangen werden. Wenn Sie jedoch Zeichenfolgen senden und empfangen möchten, müssen Sie "unpack_encoding =" utf-8 "angeben. Andernfalls sind die empfangenen Daten eine Folge von Bytes, und Sie müssen in Ihrem Programm explizit ".decode (" utf-8 ")" aufrufen. Sofern Sie keine Binärdaten senden möchten, empfiehlt es sich, standardmäßig "unpack_encoding =" utf-8 "anzugeben.

Asynchrone Ausführung

Die Verarbeitung auf der Serverseite ist nicht auf den Fall beschränkt, in dem sie sofort abgeschlossen wird, und es kann Fälle geben, in denen Sie eine Verarbeitung ausführen möchten, die Zeit benötigt. Für solche Fälle ist auch ein asynchroner Ausführungsmechanismus vorgesehen.

Die von call_async aufgerufene Methode gibt den Prozess sofort zurück und gibt das future-Objekt zurück. Das Future-Objekt gibt den Wert zurück, wenn das Ergebnis vom Server zurückgegeben wird, wenn "# get" aufgerufen wird. Wenn vom Server kein Ergebnis zurückgegeben wird, warten Sie, bis das Ergebnis vom Server erhalten wird.

Der folgende Beispielcode ist schnell zu sehen.

async_client.rb


require 'msgpack/rpc'
c = MessagePack::RPC::Client.new('localhost',18800)

puts "async call"
future1 = c.call_async(:delayed_add, 1, 1, 2)
future2 = c.call_async(:delayed_add, 1, 2, 3)
puts future2.get     #Die Reihenfolge muss nicht unbedingt die Reihenfolge des Anrufs sein
puts future1.get

async_server.rb


require 'msgpack/rpc'

class MyHandler
  def delayed_add(t,x,y)
    puts "delayed_add is called"
    as = MessagePack::RPC::AsyncResult.new
    Thread.new do
      sleep t
      as.result(x+y)
    end
    as
  end
end

Sie können das Ergebnis auch mit future.get () für Python erhalten.

async_client.py


import msgpackrpc

client = msgpackrpc.Client(msgpackrpc.Address("localhost", 18800), unpack_encoding='utf-8')
future = client.call_async('delayed_add', 3, 1, 2)
print( future.get() )

async_server.py


import msgpackrpc
import threading, time

class MyHandler(object):
    def delayed_add(self, t, x, y):
        print("delayed_add is called")
        ar = msgpackrpc.server.AsyncResult()
        def sleep_add():
            time.sleep(t)
            ar.set_result(x+y)
        thread = threading.Thread(target=sleep_add)
        thread.start()
        return ar

svr = msgpackrpc.Server( MyHandler(), unpack_encoding='utf-8' )
svr.listen( msgpackrpc.Address('localhost',18800) )
svr.start()

Rufen Sie matplotlib von Ruby aus auf

Als praktischeres Beispiel sehen Sie hier ein Beispiel für das Zeichnen eines numerischen Ruby-Arrays mit Pythons Matplotlib.

plot_server.py


import msgpackrpc
import matplotlib.pyplot as plt

svr = msgpackrpc.Server( plt, unpack_encoding='utf-8' )
svr.listen( msgpackrpc.Address('localhost',18800) )
svr.start()

plot_client.rb


require 'msgpack/rpc'
c = MessagePack::RPC::Client.new('localhost',18800)
c.timeout = Float::INFINITY

xs = -3.14.step(3.14, 0.1).to_a
ys = xs.map {|x| Math.sin(x) }
c.call( :scatter, xs, ys )
c.call( :show )

Das folgende Fenster wird angezeigt und der Plot wird gezeichnet.

image

Beachten Sie, dass der Server keine Verarbeitung zurückgibt, bis das gezeichnete Fenster geschlossen wird. Wenn es unverändert bleibt, tritt eine Zeitüberschreitung auf und auf der Clientseite tritt eine Ausnahme auf. Daher wird "c.timeout = Float :: INFINITY" festgelegt.

Hier werden die Ruby- und Python-Prozesse manuell über die Shell gestartet, aber das Starten von Python als externer Prozess im Ruby-Programm scheint eine übersichtliche Oberfläche zu sein, als würde direkt von Ruby aus geplottet. ..

Rails-Methoden aus Python aufrufen

Als Beispiel in die entgegengesetzte Richtung erhalten Sie die Informationen in der Rails-App von Python

rails_server.rb


require 'msgpack/rpc'
require File.join( ENV['RAILS_ROOT'], 'config/environment' )

Object.class_eval do
  def to_msgpack(*args)  # to_Wenn msgpack nicht definiert ist, zu_Machen Sie es zu einer Spezifikation, nach dem Aufruf von s in msgpack zu konvertieren
    to_s.to_msgpack(*args)
  end
end

class MyRailsHandler
  def get_book(name)
    Book.where(name: name).first.as_json
    # as_Hash mit json.
  end
end

svr = MessagePack::RPC::Server.new
svr.listen('localhost', 18800, MyRailsHandler.new)
svr.run

rails_client.py


import msgpackrpc

client = msgpackrpc.Client(msgpackrpc.Address("localhost", 18800), unpack_encoding='utf-8')
result = client.call('get_book', 'echo')   #Ergebnis ist Wörterbuch
print( result )

Der Punkt ist, to_msgpack (* args) für Object zu definieren. Für Klassen, für die to_msgpack nicht definiert ist, wird das hier definierte Objekt # to_msgpack (* args)` aufgerufen. Dies ermöglicht es, Zeitobjekte und dergleichen zu serialisieren.

Verarbeitung, die mit RPC schwer zu realisieren ist

RPC kann eine einfache Verarbeitung verarbeiten, bei der nur eine Methode aufgerufen wird, wie wir bisher gesehen haben. In den folgenden Fällen scheint RPC es jedoch nicht einfach zu lösen.

Recommended Posts

MessagePack-Aufruf von Ruby to Python-Methoden (oder Python to Ruby-Methoden) mithilfe von RPC
Wie man Python oder Julia von Ruby aus aufruft (experimentelle Implementierung)
[Python] Konvertieren von DICOM in PNG oder CSV
Ich möchte mit Python eine E-Mail von Google Mail senden.
Änderungen von Python 3.0 zu Python 3.5
Änderungen von Python 2 zu Python 3.0
Python aus oder importieren
PUSH-Benachrichtigung von Python an Android mithilfe der Google-API
Kopieren Sie S3-Dateien mit GSUtil von Python nach GCS
Abfrage von Python an Amazon Athena (unter Verwendung des benannten Profils)
Mit Python abflachen
Post von Python nach Slack
Anaconda aktualisiert von 4.2.0 auf 4.3.0 (python3.5 aktualisiert auf python3.6)
Mit Python auf Twitter posten
Starten Sie mit Python zu Selen
Wechseln Sie von Python2.7 zu Python3.6 (centos7)
Stellen Sie von Python aus eine Verbindung zu SQLite her
Konvertieren Sie mit Python für .NET von Pandas DataFrame in System.Data.DataTable
Ich habe versucht, die Python-Bibliothek von Ruby mit PyCall zu verwenden
Rufen Sie Matlab von Python zur Optimierung auf
So installieren Sie Python mit Anaconda
Verwenden von Rstan aus Python mit PypeR
Hinweise zur Verwendung von MeCab aus Python
Post von Python auf Facebook Timeline
So erhalten Sie mithilfe der Mastodon-API Follower und Follower von Python
[Lambda] [Python] Von Lambda auf Twitter posten!
Rufen Sie popcount von Ruby / Python / C # auf
Stellen Sie von Python aus eine Verbindung zur utf8mb4-Datenbank her
Verwenden von Cloud-Speicher aus Python3 (Einführung)
Python (vom ersten Mal bis zur Ausführung)
Poste ein Bild von Python auf Tumblr
So greifen Sie über Python auf Wikipedia zu
Python, um von einer anderen Sprache zu wechseln
Führen Sie Ansible über Python mithilfe der API aus
Vorsichtsmaßnahmen bei der Verwendung von Phantomjs aus Python
Greifen Sie mit OAuth 2.0 von Python aus auf Tabellenkalkulationen zu
Versuchen Sie es mit Amazon DynamoDB von Python
Hat sich nicht von Python 2 auf 3 geändert
Aktualisieren Sie Mac Python von 2 auf 3
Von der Vorbereitung der morphologischen Analyse mit Python unter Verwendung von Polyglot bis zur Teilwortmarkierung
Umgang mit OAuth2-Fehlern bei Verwendung von Google APIs aus Python
Erstellen Sie mit Mecab aus Python3 ein Tool, das Furigana automatisch mit HTML schüttelt
Versuchen Sie es mit Pythons Webframework Django (1) - Von der Installation bis zum Serverstart
So erhalten Sie den Wert aus dem Parameterspeicher in Lambda (mit Python)
[Einführung in die Udemy Python3 + -Anwendung] 18. Listenmethode
Einführung in die diskrete Ereignissimulation mit Python # 1
Binden Sie Methoden an Python-Klassen und -Instanzen
So aktualisieren Sie Google Sheets von Python
Privates Python-Handbuch (von Zeit zu Zeit aktualisiert)
Ich möchte ein Glas aus Python verwenden
Konvertieren Sie von Katakana zu Vokal Kana [Python]
Push-Benachrichtigung vom Python-Server an Android
Melden Sie sich mit Anforderungen in Python bei Slack an
Referenz der INI-Datei in Python oder Ruby
Herstellen einer Verbindung von Python zu MySQL unter CentOS 6.4
Ich habe versucht, die UnityCloudBuild-API von Python zu verwenden
Portieren und Ändern des Doublet-Solvers von Python2 auf Python3.
Versuchen Sie, Excel mit Python (Xlwings) zu betreiben.
Zugriff auf RDS von Lambda (Python)