GRPC beginnend mit Python

Überblick

gRPC ist ein modernes, leistungsstarkes Open-Source-RPC-Framework (Remoto Protocol Call), das in jeder Umgebung ausgeführt werden kann. Es hat den Vorteil, dass Daten mithilfe von Protokollpuffern serialisiert und eine Hochgeschwindigkeitskommunikation erreicht werden können. Es ist mit verschiedenen Sprachen und Plattformen kompatibel und bidirektionales Streaming unter Verwendung von http / 2 ist möglich. Sie können einfach Dienste (Daten und Funktionen für die Kommunikation) mithilfe von Protokollpuffern definieren und die API-Spezifikationen klären.

git: k-washi/stereophonic-Sound-System/proto

Der gRPC-Artikel von Golang versin ist in [GRPC beginnend mit Golang] zu finden (https://qiita.com/kwashi/items/533bbb7d09e723c8b56f).

Inhalt

In diesem Abschnitt wird beschrieben, wie Sie mit gRPC auf eine Anfrage eines Clients mit der Position (x, y, z) eines vom Server berechneten geeigneten Objekts antworten. Ursprünglich handelt es sich um ein System, das je nach Position des Charakters stereophonen Klang erzeugt und zur Übertragung von Positionsinformationen entwickelt wurde.

Bibliotheksinstallation

pip install grpcio-tools==1.26.0

Protokolldefinition

Definieren Sie die Positionen x, y, z als Pos in der .proto-Datei, wie unten gezeigt. Dann wird Position zu einem Protokoll (Kommunikationskonvention), das Standortinformationen enthält. Andererseits wird das Msg-Protokoll als Ergebnis der Ausgabe einer Nachricht definiert, in der Standortinformationen an die Serverseite angefordert werden, oder als Ausgabe von Standortinformationen. Darüber hinaus sind PositionReq und PositionPub als Funktionen für die Kommunikation definiert. PositionReq ist eine Funktion, die Nachrichten an den Server sendet und Positionsinformationen vom Server empfängt, und PositionPub ist eine Funktion, die Positionsinformationen an den Server sendet und Nachrichten empfängt. In diesem Artikel wird anhand eines Beispiels mit PositionReq erläutert.

proto/position.proto


syntax = "proto3";

package posXYZ;
option go_package="posXYZpb";

message Pos {
  float x = 1;
  float y = 2;
  float z = 3;
}

//client streaming
message Position{
  Pos position = 1;
  int32 status = 2;
  string msg = 3;
}

message Msg{
  int32 status = 1;
  string msg = 2;
}


service PositionService{
  
  rpc PositionReq(Msg) returns (Position) {};
  rpc PositionPub(Position) returns (Msg) {};
}

Konvertierung in Protokollpuffer für Python

Wie in Golang Versins gRPC-Artikel gRPC beginnend mit Golang beschrieben, sieht es wie dieser Artikel aus, selbst wenn es in einen Protokollpuffer für Golang konvertiert wird. Selbst wenn Sie in den Protokollpuffer für Python konvertieren, basiert die Konvertierung auf der obigen Protokolldefinition. Durch die Konvertierung in diesen Protokollpuffer werden die Struktur jeder in jeder Sprache definierten Nachricht und das Definitionsdokument (Programm) einschließlich der Servicefunktion ausgegeben.

Python kann durch Ausführen des folgenden Programms konvertiert werden.

proto/codegen.py


from grpc.tools import protoc

protoc.main(
    (
        '',
        '-I.',
        '--python_out=.',
        '--grpc_python_out=.',
        './proto/position.proto',
    )
)
python ./proto/codegen.py

Als Ergebnis des obigen Befehls werden position_pb2.py generiert, das die in der Protokolldatei definierte Nachricht definiert, und position_pb2_grpc.py, das die für die gRPC-Kommunikation verwendete Funktion definiert.

Serverseitige Implementierung

Implementieren Sie hier einen Server, der die Anforderungsnachricht empfängt und Position (Standortinformationen) ausgibt. Die hier ausgegebene Positionsinformation ist eine Position, die sich dreht, während ein Abstand von 1 m von (x, y, z) = (0, 0, 0) eingehalten wird.

In Bezug auf configInit für Einstellungen, die nicht mit gRPC und logger für die Protokollierung zusammenhängen, mein früherer Artikel Parametereinstellung durch python configparser, [Python-Protokollierung Weitere Informationen finden Sie unter Verwendung des Moduls.

Die PositionServer-Klasse überlastet den in position_pb2_grpc.py definierten PositionServerServer und definiert die PositionReq-Funktion, die Positionsinformationen als Antwort auf eine Anforderung zurückgibt. Dieser Rückgabewert Position verwendet den in position_pb2.py definierten Wert. Darüber hinaus definiert diese Klasse auch Funktionen, die Standortinformationen x, y und z speichern und ausgeben und Standortinformationen verwalten.

Die Serverklasse ist eine Klasse, die die von der Serverseite von gRPC durchgeführte Verarbeitung zusammenfasst. Daher hat es eine Instanz der PosotionServer-Klasse als Variable. Die Startfunktion definiert den Prozess zum Starten des gRPC-Servers und die Stoppfunktion definiert den Prozess zum Stoppen des gRPC-Servers. Da es sich bei diesen Start- und Stoppprozessen um feste Phrasen handelt, ändert sich der grundlegende Ablauf in keinem Programm.

Im Hauptprozess wird der Server durch Ausführen der Startfunktion geöffnet, und der Prozess auf der Serverseite von gRPC ist beendet. Um die Standortinformationen stündlich zu ändern, werden hier die von posServer.pubPos (x, y, z) ausgegebenen Standortinformationen überschrieben.

proto/server.py


import os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

# ------------

from utils.config import configInit
Conf = configInit()
logger = Conf.setLogger(__name__)

# ------------
#grpc

import grpc
from proto.position_pb2 import *
from proto import position_pb2_grpc

# ------------

from concurrent import futures

class PositionService(position_pb2_grpc.PositinServiceServicer):
  def __init__(self):
    self.x = 1.
    self.y = 0.
    self.z = 0.

  def PositionReq(self, request, context):
    try:
      is_success = 0
    except:
      is_success = -1
    return Position(
      position = Pos(
        x = self.x, y = self.y, z = self.z
      ),
      status = is_success,
      msg = "character position"
    )

  def pubPos(self, x, y, z):
    self.x, self.y, self.z = x, y, z
  
  def getPos(self, x, y, z):
    return self.x, self.y, self.z

class Server():
  def __init__(self):
    self.posServer = PositionService()

  def start(self):
    
    self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=3))
    position_pb2_grpc.add_PositinServiceServicer_to_server(
      self.posServer, self.server
    )

    self.server.add_insecure_port(Conf.PosServer)
    self.server.start()
    logger.info("Start server {0}".format(Conf.PosServer))

  def stop(self):
    self.server.stop(0)

if __name__ == "__main__":
  import time
  import numpy as np
  server = Server()
  server.start()
  
  z = 0.
  azimuth = 0.
  aziShift = 5* np.pi / 180.

  def azi2pos(azimuth):
    x = np.cos(azimuth)
    y = np.sin(azimuth)
    return x, y

  try:
    while True:
      time.sleep(0.1)
      azimuth += aziShift
      x,y = azi2pos(azimuth)
      server.posServer.pubPos(x,y,z)

  except Exception as e:
    logger.critical(e)
    server.stop()

Client-seitige Implementierung

Die clientseitige Implementierung ist in der posClient-Klasse implementiert. Starten Sie die Client-Verarbeitung mit der Open-Funktion. Beachten Sie, dass position_pb2_grpc.PositinServiceStub die Funktionen enthält, die die Clientseite ausführt. Daher kann in der Funktion posRequest Msg von der Funktion self.stub.PositionReq gesendet werden, und die Informationen vom Server können als Rückgabewert abgerufen werden. Danach können Sie jedes Mal, wenn Sie posRequest () im Hauptprozess ausführen, mit der Serverseite kommunizieren und die Standortinformationen abrufen.

proto/client.py


mport os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

# ------------

from utils.config import configInit
Conf = configInit()
logger = Conf.setLogger(__name__)

# ------------
#grpc

import grpc
from proto.position_pb2 import *
from proto import position_pb2_grpc

class posClient():
  def __init__(self):
    self.x = 0.
    self.y = 0.
    self.z = 0.

  def posRequest(self):
    request = Msg(
      status = 0,
      msg = "request pos"
    )
    res = self.stub.PositionReq(request)
    if res.status == 0:
      logger.info("PositionRes {0}, {1}, x:{2}, y:{3}, z:{4}".format(res.status, res.msg, res.position.x, res.position.y, res.position.z))
      self.x, self.y, self.z = res.position.x, res.position.y, res.position.z
      return True
    
    logger.error("Position Response Error")
    return False

  
  def open(self):
    self.channel = grpc.insecure_channel(Conf.PosClient)
    self.stub = position_pb2_grpc.PositinServiceStub(self.channel)
    logger.info("Open position client channel: {0}".format(Conf.PosClient))

  def close(self):
    self.channel.close()
  
  def getPos(self):
    return self.x, self.y, self.z
  
if __name__ == "__main__":
  import time
  posCl = posClient()
  posCl.open()
  while True:
    time.sleep(1)
    try:
      ok = posCl.posRequest()
      if ok:
        x, y, z = posCl.getPos()
        logger.info("{0}, {1}, {2}".format(x, y, z))
    except Exception as e:
      logger.error("client error {0}".format(e))
  posCl.close()

Zusammenfassung

Mit den oben genannten Informationen können die Standortinformationen per Python mit gRPC ausgetauscht werden. Ich denke, gRPC wird eine Technologie sein, die in Zukunft in vielen Situationen eingesetzt wird, da sie Vorteile bietet, wie beispielsweise die einfachere Erstellung von in mehreren Sprachen geschriebenen Mikrodiensten. Bitte probieren Sie es aus.

Recommended Posts

GRPC beginnend mit Python
Python ab Windows 7
Verbessertes Lernen ab Python
Ich habe gRPC mit Python ausprobiert
Python beginnend mit Hallo Welt!
Datenanalyse beginnend mit Python (Datenvisualisierung 1)
Datenanalyse beginnend mit Python (Datenvisualisierung 2)
FizzBuzz in Python3
Scraping mit Python
Scraping mit Python
Python mit Go
Twilio mit Python
In Python integrieren
Spielen Sie mit 2016-Python
AES256 mit Python
Getestet mit Python
Python beginnt mit ()
mit Syntax (Python)
Bingo mit Python
Zundokokiyoshi mit Python
Excel mit Python
Mikrocomputer mit Python
Mit Python besetzen
Kommunizieren Sie mit gRPC zwischen Elixir und Python
Systemhandel ab Python3: langfristige Investition
"Systemhandel beginnt mit Python3" Lesememo
Geschäftseffizienz von Grund auf mit Python
Datenanalyse beginnend mit Python (Datenvorverarbeitung - maschinelles Lernen)
"Erste elastische Suche" beginnend mit einem Python-Client
Serielle Kommunikation mit Python
Zip, entpacken mit Python
Django 1.11 wurde mit Python3.6 gestartet
Python mit Eclipse + PyDev.
Socket-Kommunikation mit Python
Datenanalyse mit Python 2
Scraping in Python (Vorbereitung)
Versuchen Sie es mit Python.
Python lernen mit ChemTHEATER 03
Sequentielle Suche mit Python
Maschinelles Lernen beginnend mit Python Personal Memorandum Part2
"Objektorientiert" mit Python gelernt
Umgang mit Yaml mit Python
Löse AtCoder 167 mit Python
Serielle Kommunikation mit Python
[Python] Verwenden Sie JSON mit Python
Python lernen mit ChemTHEATER 05-1
Lerne Python mit ChemTHEATER
Führen Sie prepDE.py mit python3 aus
1.1 Erste Schritte mit Python
Tweets mit Python sammeln
Binarisierung mit OpenCV / Python
3. 3. KI-Programmierung mit Python
Kernel-Methode mit Python
Maschinelles Lernen beginnend mit Python Personal Memorandum Part1
Scraping mit Python + PhantomJS
Fahren Sie WebDriver mit Python
[Python] Mit CGIHTTPServer umleiten
Sprachanalyse mit Python
Denken Sie an Yaml mit Python
Kinesis mit Python betreiben
Verwenden Sie DynamoDB mit Python