Начало работы с Python gRPC

Java Python переводчик gRPC

Первоначально разработанная Google, gRPC является независимой от языка и платформы системой удаленного вызова процедур (RPC) с открытым исходным кодом. В этой статье вы познакомитесь с gRPC на простом примере Hello World.

Что такое gRPC?

gRPC также основан на идее определенияСлужить, указав методы (включая параметры и возвращаемые типы), которые можно вызывать удаленно. Реализуйте этот интерфейс на стороне сервера и запустите сервер gRPC для обработки клиентских вызовов. есть клиентзаглушкаМожно сделать так же, как сервер.

в gRPCклиентПриложение может напрямую вызывать другую машину, например локальный объект.СерверПрикладной подход упрощает создание распределенных приложений и сервисов.

gPRC

Клиенты и серверы gRPC могут работать и взаимодействовать в различных средах и могут быть написаны на любом языке, поддерживаемом gRPC.

gRPC поддерживает C++ Java Python Go Ruby C# Node.js PHP Dart и другие языки

gRPC использует по умолчаниюprotocol buffers, который представляет собой легкий и эффективный формат хранения структурированных данных с открытым исходным кодом Google, который можно использовать для сериализации структурированных данных или сериализации. Это хорошее хранилище данных или формат обмена данными RPC.

Установите буферы протокола Google

Способ 1 (рекомендуется)

Справочная документация:gRPC Python Quickstart

1. Установите gRPC

python -m pip install grpcio
# 或者
sudo python -m pip install grpcio

# 在 El Capitan OSX 系统下可能会看到以下报错

$ OSError: [Errno 1] Operation not permitted: '/tmp/pip-qwTLbI-uninstall/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/six-1.4.1-py2.7.egg-info'

# 可以使用以下命令
python -m pip install grpcio --ignore-installed
2. Установите инструменты gRPC

Инструменты Python gPRC содержат компилятор буфера протокола и.protoПлагины для сервера генерации файлов и клиентского кода

python -m pip install grpcio-tools

Способ второй:

на странице гитхабаprotobuf BuffersВы можете скачать бинарный исходный код.После загрузки выполните следующую команду для установки:

tar -zxvf protobuf-all-3.5.1.tar
cd protobuf-all-3.5.1
./configure
make
make install

>> protoc --version
libprotoc 3.5.1  # 安装成功

Поскольку вы хотите использовать тестирование Protobuf + Python, вам также необходимо установить среду выполнения python.protobuf Буферы Python документация

# 打开 python 目录
cd python
python setup.py install  # 安装 python 运行环境

Основное использование Protobuf

определить тип сообщения

Начнем с очень простого примера. Предположим, вы хотите определить формат сообщения «поискового запроса».Каждый запрос содержит строку запроса, количество страниц, на которых расположены интересующие вас результаты запроса, и количество результатов запроса на страницу. Файл .proto типа сообщения можно определить следующим образом:

syntax = "proto3";  // 声明使用 proto3 语法

message SearchRequest {
  string query = 1;  // 每个字段都要指定数据类型
  int32 page_number = 2; // 这里的数字2 是标识符,最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999]
  int32 result_per_page = 3; // 这里是注释,使用 //
}
  • В первой строке статьи указано, что вы используете синтаксис proto3: если он не указан, компилятор будет использовать proto2.这个指定语法必须是文件的非空非注释的第一行.
  • SearchRequestФормат сообщения имеет три поля, и данные, содержащиеся в сообщении, соответствуют каждому полю. Каждое из этих полей имеет имя и тип.
  • Добавьте комментарии к файлам .proto, вы можете использовать стиль C/C++/java.双斜杠(//)Синтаксический формат.
  • В теле сообщения каждое поле имеет уникальный числовой идентификатор. Эти идентификаторы используются для идентификации отдельных полей в двоичном формате сообщения и не могут быть изменены после их использования.

Идентификационный номер в пределах [1,15] будет занимать один байт при кодировании. Идентификационный номер в пределах [16,2047] занимает 2 байта. Следовательно, идентификационные номера в пределах [1,15] должны быть зарезервированы для тех элементов сообщения, которые появляются часто. ВАЖНО: Зарезервируйте некоторые идентификаторы для часто встречающихся идентификаторов, которые могут быть добавлены в будущем.

Укажите правила поля

Указанный модификатор поля сообщения должен быть одним из следующих:

  • единственное число: правильно сформированное сообщение должно иметь 0 или 1 из этих полей (но не более 1).

  • Repeat: это поле может повторяться любое количество раз (включая ноль) в правильно сформированном сообщении. Порядок повторяющихся значений сохраняется.

    В proto3 повторяющееся скалярное поле по умолчанию использует Packed.

    message Test4 {
      repeated int32 d = 4 [packed=true];
    }
    

Числовой тип

Поле скалярного сообщения может содержать один из следующих типов — в этой таблице показаны типы, определенные в файле .proto, и соответствующие типы, определенные в автоматически сгенерированном классе доступа:

.proto Type Notes C++ Type Java Type Python Type[2] Go Type Ruby Type
double double double float float64 Float
float float float float float32 Float
int32 Используйте кодировку переменной длины, которая неэффективна для отрицательных значений. Если в вашем поле могут быть отрицательные значения, используйте вместо этого sint64. int32 int int int32 Fixnum или Bignum (при необходимости)
uint32 Использовать кодировку переменной длины uint32 int int/long uint32 Fixnum или Bignum (при необходимости)
uint64 Использовать кодировку переменной длины uint64 long int/long uint64 Bignum
sint32 Используйте кодировки переменной длины, которые намного эффективнее, чем int32 для отрицательных значений. int32 int int int32 Fixnum или Bignum (при необходимости)
sint64 Целочисленное значение со знаком, использующее кодировку переменной длины. Более эффективен, чем обычный int64 при кодировании. int64 long int/long int64 Bignum
fixed32 Всегда 4 байта, этот тип более эффективен, чем uint32, если значение всегда больше 228. uint32 int int uint32 Fixnum или Bignum (при необходимости)
fixed64 Всегда 8 байт, этот тип более эффективен, чем uint64, если значение всегда больше 256. uint64 long int/long uint64 Bignum
sfixed32 всегда 4 байта int32 int int int32 Fixnum или Bignum (при необходимости)
sfixed64 всегда 8 байт int64 long int/long int64 Bignum
bool bool boolean bool bool TrueClass/FalseClass
string Строка должна быть в кодировке UTF-8 или 7-битном кодированном тексте ASCII. string String str/unicode string String (UTF-8)
bytes Может содержать байтовые данные в любом порядке. string ByteString str []byte String (ASCII-8BIT)

По умолчанию

Когда сообщение анализируется, если закодированное сообщение не содержит определенного единственного элемента, поле, соответствующее блокировке анализируемого объекта, устанавливается в значение по умолчанию, указанное для различных типов следующим образом:

  • Для строк по умолчанию используется пустая строка.

  • Для байтов по умолчанию используются пустые байты.

  • Для логических значений значение по умолчанию равно false

  • Для числовых типов значение по умолчанию равно 0.

  • Для перечислений по умолчанию используется первое определенное значение перечисления, которое должно быть равно 0;

  • Для типа сообщения (message) поле не задается, точное сообщение определяется языком, подробнее см.generated code guide

    Значение по умолчанию для повторяющихся полей пусто (обычно это пустой список на соответствующем языке).

вложенный тип

Вы можете определить и использовать типы сообщений в других типах сообщений.В следующем примере сообщение Result определено в сообщении SearchResponse, например:

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  repeated Result results = 1;
}

В сообщении SearchResponse определяются вложенные сообщенияResult, и используется для определенияSearchResponseв сообщенииresultsплощадь.

Компиляция файла protobuf

Что генерируется из файла .proto?

При запуске файла .proto с компилятором буфера протокола компилятор будет генерировать код на выбранном языке, который может манипулировать типами сообщений, определенными в файле .proto, включая получение, установку значений полей и сериализацию сообщения в выходной поток. и анализировать сообщения из входного потока.

  • Для C++ компилятор создает файл .h и файл .cc для каждого файла .proto, и каждое сообщение в файле .proto имеет соответствующий класс.
  • Для Java компилятор создает файл .java для каждого типа сообщения, а также специальный класс Builder (который используется для создания интерфейса класса сообщения).
  • Для Python все немного иначе — компилятор Python генерирует модуль со статическим дескриптором для каждого типа сообщения в файле .proto, который во время выполнения объединяется с метаклассом и используется для создания необходимых классов доступа к данным Python.
  • Для go компилятор создает файл .pd.go для каждого типа сообщения.
  • Для Ruby компилятор создает файл .rb для каждого типа сообщения.
  • Для javaNano вывод компилятора аналогичен домену java, но без класса Builder.
  • Для Objective-C компилятор создает файл pbobjc.h и файл pbobjcm для каждого типа сообщения, и каждое сообщение в файле .proto имеет соответствующий класс.
  • Для C# компилятор создает файл .cs для каждого типа сообщения, и каждое сообщение в файле .proto имеет соответствующий класс.

Пример gRPC на Python

компилировать

Здесь мы скомпилируем его с помощью Python и посмотрим, что мы получим:

// 文件名 hello.proto
syntax = "proto3";

package hello;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Скомпилируйте с помощью следующей команды:

python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. ./hello.proto

Генерируются два файла:

  • hello_pb2.pyЭтот файл содержит сгенерированный запрос (HelloRequest) и ответ(HelloReply) своего рода.
  • hello_pb2_grpc.pyЭтот файл содержит сгенерированный клиент (GreeterStub) и сервер (GreeterServicer) тип.

Адрес источникаGitHub.com/персональный компьютер/персональный компьютер/нет…

Хотя серверный и клиентский код сгенерированы, нам все еще нужно вручную реализовать и вызвать методы.

Создать код сервера

Создайте и запуститеGreeterУслугу можно разделить на две части:

  • Реализуйте сгенерированный интерфейс службы, определенный нашей службой: функция, которая выполняет фактическую «работу» нашей службы.

  • Запустите сервер gRPC, который прослушивает запросы от клиентов и передает ответы от службы.

В текущем каталоге откройте файл Greeter_server.py и реализуйте новую функцию:

from concurrent import futures
import time

import grpc

import hello_pb2
import hello_pb2_grpc

_ONE_DAY_IN_SECONDS = 60 * 60 * 24


class Greeter(hello_pb2_grpc.GreeterServicer):
	# 工作函数
    def SayHello(self, request, context):
        return hello_pb2.HelloReply(message='Hello, %s!' % request.name)


def serve():
    # gRPC 服务器
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()  # start() 不会阻塞,如果运行时你的代码没有其它的事情可做,你可能需要循环等待。
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        server.stop(0)

if __name__ == '__main__':
    serve()

Обновить код клиента

В текущем каталоге откройте файл Greeter_client.py и реализуйте новую функцию:

from __future__ import print_function

import grpc

import hello_pb2
import hello_pb2_grpc


def run():
    channel = grpc.insecure_channel('localhost:50051')
    stub = hello_pb2_grpc.GreeterStub(channel)
    response = stub.SayHello(hello_pb2.HelloRequest(name='goodspeed'))
    print("Greeter client received: " + response.message)


if __name__ == '__main__':
    run()

Для методов RPC, которые возвращают один ответ («унарные ответы»), gRPC Python поддерживает как синхронную (блокирующую), так и асинхронную (неблокирующую) семантику потока управления. Для методов RPC с потоковой передачей ответов вызов немедленно возвращает итератор значений ответа. вызовите итераторnext()Метод блокируется до тех пор, пока не станет доступен ответ от итератора.

запустить код

  1. Сначала запустите код сервера
python greeter_server.py
  1. затем запустите клиентский код
python greeter_client.py
# output

Greeter client received: Hello, goodspeed!

Исходный адрес: https://github.com/grpc/grpc/tree/master/examples/python.

Ссылка на ссылку


Наконец, поблагодарите мою девушку за ее поддержку и терпимость, чем ❤️

Вы также можете ввести следующие ключевые слова в официальном аккаунте, чтобы получить исторические статьи:公号&小程序 | 设计模式 | 并发&协程