摘要:消息格式有三個字段,在消息中承載的數(shù)據(jù)分別對應(yīng)于每一個字段。所以應(yīng)該為那些頻繁出現(xiàn)的消息元素保留之內(nèi)的標(biāo)識號。示例編譯這里我們用編譯一下,看得到什么文件名使用以下命令編譯生成了兩個文件此文件包含生成的和類。
gRPC 一開始由 google 開發(fā),是一款語言中立、平臺中立、開源的遠(yuǎn)程過程調(diào)用(RPC)系統(tǒng)。 本文通過一個簡單的 Hello World 例子來向您介紹 gRPC 。gRPC 是什么?
gRPC 也是基于以下理念:定義一個服務(wù),指定其能夠被遠(yuǎn)程調(diào)用的方法(包含參數(shù)和返回類型)。在服務(wù)端實(shí)現(xiàn)這個接口,并運(yùn)行一個 gRPC 服務(wù)器來處理客戶端調(diào)用。在客戶端擁有一個存根能夠像服務(wù)端一樣的方法。
在 gRPC 里客戶端應(yīng)用可以像調(diào)用本地對象一樣直接調(diào)用另一臺不同的機(jī)器上服務(wù)端應(yīng)用的方法,使得我們能夠更容易地創(chuàng)建分布式應(yīng)用和服務(wù)。
gRPC 客戶端和服務(wù)端可以在多種環(huán)境中運(yùn)行和交互,并且可以用任何 gRPC 支持的語言來編寫。
gRPC 支持 C++ Java Python Go Ruby C# Node.js PHP Dart 等語言
gRPC 默認(rèn)使用 protocol buffers,這是 Google 開源的一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲格式,可以用于結(jié)構(gòu)化數(shù)據(jù)串行化,或者說序列化。它很適合做數(shù)據(jù)存儲或 RPC 數(shù)據(jù)交換格式。
安裝 Google Protocol Buffer 方法一(建議使用)參考文檔:gRPC Python Quickstart
python -m pip install grpcio # 或者 sudo python -m pip install grpcio # 在 El Capitan OSX 系統(tǒng)下可能會看到以下報錯 $ 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
Python gPRC tools 包含 protocol buffer 編譯器和用于從 .proto 文件生成服務(wù)端和客戶端代碼的插件
python -m pip install grpcio-tools方法二:
在 github 頁面protobuf Buffers可以下載二進(jìn)制源碼,下載后執(zhí)行以下命令安裝:
tar -zxvf protobuf-all-3.5.1.tar cd protobuf-all-3.5.1 ./configure make make install >> protoc --version libprotoc 3.5.1 # 安裝成功
因?yàn)槭且褂?Protobuf + Python 測試,所以還要安裝 python運(yùn)行環(huán)境。protobuf Buffers python 文檔
# 打開 python 目錄 cd python python setup.py install # 安裝 python 運(yùn)行環(huán)境Protobuf 基本使用 定義一個消息類型
先來看一個非常簡單的例子。假設(shè)你想定義一個“搜索請求”的消息格式,每一個請求含有一個查詢字符串、你感興趣的查詢結(jié)果所在的頁數(shù),以及每一頁多少條查詢結(jié)果。可以采用如下的方式來定義消息類型的.proto文件了:
syntax = "proto3"; // 聲明使用 proto3 語法 message SearchRequest { string query = 1; // 每個字段都要指定數(shù)據(jù)類型 int32 page_number = 2; // 這里的數(shù)字2 是標(biāo)識符,最小的標(biāo)識號可以從1開始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999] int32 result_per_page = 3; // 這里是注釋,使用 // }
文章的第一行指定了你正在使用 proto3 語法:如果不指定,編譯器會使用 proto2。這個指定語法必須是文件的非空非注釋的第一行。
SearchRequest消息格式有三個字段,在消息中承載的數(shù)據(jù)分別對應(yīng)于每一個字段。其中每個字段都有一個名字和一種類型。
向.proto文件添加注釋,可以使用C/C++/java風(fēng)格的雙斜杠(//) 語法格式。
在消息體中,每個字段都有唯一的一個數(shù)字標(biāo)識符。這些標(biāo)識符用來在消息的二進(jìn)制格式中識別各個字段,一旦開始使用就不能再改變。
[1,15]之內(nèi)的標(biāo)識號在編碼的時候會占用一個字節(jié)。[16,2047]之內(nèi)的標(biāo)識號則占用2個字節(jié)。所以應(yīng)該為那些頻繁出現(xiàn)的消息元素保留 [1,15]之內(nèi)的標(biāo)識號。切記:要為將來有可能添加的、頻繁出現(xiàn)的標(biāo)識號預(yù)留一些標(biāo)識號。指定字段規(guī)則
所指定的消息字段修飾符必須是如下之一:
singular:一個格式良好的消息應(yīng)該有0個或者1個這種字段(但是不能超過1個)。
repeated:在一個格式良好的消息中,這種字段可以重復(fù)任意多次(包括0次)。重復(fù)的值的順序會被保留。
在proto3中,repeated的標(biāo)量域默認(rèn)情況蝦使用packed。
message Test4 { repeated int32 d = 4 [packed=true]; }數(shù)值類型
一個標(biāo)量消息字段可以含有一個如下的類型——該表格展示了定義于.proto文件中的類型,以及與之對應(yīng)的、在自動生成的訪問類中定義的類型:
.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 | 使用變長編碼,對于負(fù)值的效率很低,如果你的域有可能有負(fù)值,請使用sint64替代 | int32 | int | int | int32 | Fixnum 或者 Bignum(根據(jù)需要) |
uint32 | 使用變長編碼 | uint32 | int | int/long | uint32 | Fixnum 或者 Bignum(根據(jù)需要) |
uint64 | 使用變長編碼 | uint64 | long | int/long | uint64 | Bignum |
sint32 | 使用變長編碼,這些編碼在負(fù)值時比int32高效的多 | int32 | int | int | int32 | Fixnum 或者 Bignum(根據(jù)需要) |
sint64 | 使用變長編碼,有符號的整型值。編碼時比通常的int64高效。 | int64 | long | int/long | int64 | Bignum |
fixed32 | 總是4個字節(jié),如果數(shù)值總是比總是比228大的話,這個類型會比uint32高效。 | uint32 | int | int | uint32 | Fixnum 或者 Bignum(根據(jù)需要) |
fixed64 | 總是8個字節(jié),如果數(shù)值總是比總是比256大的話,這個類型會比uint64高效。 | uint64 | long | int/long | uint64 | Bignum |
sfixed32 | 總是4個字節(jié) | int32 | int | int | int32 | Fixnum 或者 Bignum(根據(jù)需要) |
sfixed64 | 總是8個字節(jié) | int64 | long | int/long | int64 | Bignum |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | |
string | 一個字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本。 | string | String | str/unicode | string | String (UTF-8) |
bytes | 可能包含任意順序的字節(jié)數(shù)據(jù)。 | string | ByteString | str | []byte | String (ASCII-8BIT) |
當(dāng)一個消息被解析的時候,如果被編碼的信息不包含一個特定的singular元素,被解析的對象鎖對應(yīng)的域被設(shè)置位一個默認(rèn)值,對于不同類型指定如下:
對于strings,默認(rèn)是一個空string
對于bytes,默認(rèn)是一個空的bytes
對于bools,默認(rèn)是false
對于數(shù)值類型,默認(rèn)是0
對于枚舉,默認(rèn)是第一個定義的枚舉值,必須為0;
對于消息類型(message),域沒有被設(shè)置,確切的消息是根據(jù)語言確定的,詳見generated code guide
對于可重復(fù)域的默認(rèn)值是空(通常情況下是對應(yīng)語言中空列表)。
嵌套類型你可以在其他消息類型中定義、使用消息類型,在下面的例子中,Result消息就定義在SearchResponse消息內(nèi),如:
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; }
在 message SearchResponse 中,定義了嵌套消息 Result,并用來定義SearchResponse消息中的results域。
Protobuf 文件編譯 從.proto文件生成了什么?當(dāng)用protocol buffer編譯器來運(yùn)行.proto文件時,編譯器將生成所選擇語言的代碼,這些代碼可以操作在.proto文件中定義的消息類型,包括獲取、設(shè)置字段值,將消息序列化到一個輸出流中,以及從一個輸入流中解析消息。
對C++來說,編譯器會為每個.proto文件生成一個.h文件和一個.cc文件,.proto文件中的每一個消息有一個對應(yīng)的類。
對Java來說,編譯器為每一個消息類型生成了一個.java文件,以及一個特殊的Builder類(該類是用來創(chuàng)建消息類接口的)。
對Python來說,有點(diǎn)不太一樣——Python編譯器為.proto文件中的每個消息類型生成一個含有靜態(tài)描述符的模塊,,該模塊與一個元類(metaclass)在運(yùn)行時(runtime)被用來創(chuàng)建所需的Python數(shù)據(jù)訪問類。
對go來說,編譯器會位每個消息類型生成了一個.pd.go文件。
對于Ruby來說,編譯器會為每個消息類型生成了一個.rb文件。
javaNano來說,編譯器輸出類似域java但是沒有Builder類
對于Objective-C來說,編譯器會為每個消息類型生成了一個pbobjc.h文件和pbobjcm文件,.proto文件中的每一個消息有一個對應(yīng)的類。
對于C#來說,編譯器會為每個消息類型生成了一個.cs文件,.proto文件中的每一個消息有一個對應(yīng)的類。
Python gRPC 示例 編譯這里我們用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 此文件包含生成的 request(HelloRequest) 和 response(HelloReply) 類。
hello_pb2_grpc.py 此文件包含生成的 客戶端(GreeterStub)和服務(wù)端(GreeterServicer)的類。
源碼地址為https://github.com/grpc/grpc/blob/master/examples/protos/helloworld.proto
雖然現(xiàn)在已經(jīng)生成了服務(wù)端和客戶端代碼,但是我們還需要手動實(shí)現(xiàn)以及調(diào)用的方法。
創(chuàng)建服務(wù)端代碼創(chuàng)建和運(yùn)行 Greeter 服務(wù)可以分為兩個部分:
實(shí)現(xiàn)我們服務(wù)定義的生成的服務(wù)接口:做我們的服務(wù)的實(shí)際的“工作”的函數(shù)。
運(yùn)行一個 gRPC 服務(wù)器,監(jiān)聽來自客戶端的請求并傳輸服務(wù)的響應(yīng)。
在當(dāng)前目錄,打開文件 greeter_server.py,實(shí)現(xiàn)一個新的函數(shù):
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): # 工作函數(shù) def SayHello(self, request, context): return hello_pb2.HelloReply(message="Hello, %s!" % request.name) def serve(): # gRPC 服務(wù)器 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() 不會阻塞,如果運(yùn)行時你的代碼沒有其它的事情可做,你可能需要循環(huán)等待。 try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0) if __name__ == "__main__": serve()更新客戶端代碼
在當(dāng)前目錄,打開文件 greeter_client.py,實(shí)現(xiàn)一個新的函數(shù):
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()
對于返回單個應(yīng)答的 RPC 方法("response-unary" 方法),gRPC Python 同時支持同步(阻塞)和異步(非阻塞)的控制流語義。對于應(yīng)答流式 RPC 方法,調(diào)用會立即返回一個應(yīng)答值的迭代器。調(diào)用迭代器的 next() 方法會阻塞,直到從迭代器產(chǎn)生的應(yīng)答變得可用。運(yùn)行代碼
首先運(yùn)行服務(wù)端代碼
python greeter_server.py
然后運(yùn)行客戶端代碼
python greeter_client.py # output Greeter client received: Hello, goodspeed!
源碼地址: https://github.com/grpc/grpc/tree/master/examples/python參考鏈接
gRPC 官方文檔中文版
Protobuf3語言指南
Google Protocol Buffer 的使用和原理
gRPC Python Quickstart
最后,感謝女朋友支持和包容,比??
也可以在公號輸入以下關(guān)鍵字獲取歷史文章:公號&小程序 | 設(shè)計(jì)模式 | 并發(fā)&協(xié)程
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/41842.html
摘要:針對這種情況提供了,可以將訓(xùn)練好的模型直接上線并提供服務(wù)。在年的開發(fā)者上便提出了。在實(shí)際的生產(chǎn)環(huán)境中比較廣泛使用的通信手段是基于的,幸運(yùn)的是從以后,也正式支持通信方式了。前 ?言 大家習(xí)慣使用TensorFlow進(jìn)行模型的訓(xùn)練、驗(yàn)證和預(yù)測,但模型完善之后的生產(chǎn)上線流程,就變得五花八門了。針對這種情況Google提供了TensorFlow Servering,可以將訓(xùn)練好的模型直接上線并...
摘要:腳本列出了在結(jié)束時安裝的映像。在不同的體系結(jié)構(gòu),將用標(biāo)識體系結(jié)構(gòu)的字符串替換。提供了許多來支持各種編程語言,官方發(fā)布了兩款針對和的和文檔。。 入門 在我們開始之前,如果你還沒有這樣做,你可能希望檢查是否已經(jīng)在開發(fā)區(qū)塊鏈應(yīng)用程序和/或運(yùn)行Hyperledger Fabric的平臺上安裝了所有前提條件。 一旦安裝了前提條件,就可以下載并安裝HyperLedger Fabric了,當(dāng)我們在F...
摘要:原文地址從實(shí)踐到原理,帶你參透在語言中大放異彩,越來越多的小伙伴在使用,最近也在公司安利了一波,希望能通過這篇文章能帶你一覽的愛與恨。幀的主要作用是裝填主體信息,是數(shù)據(jù)幀。 showImg(https://segmentfault.com/img/remote/1460000019552245); 原文地址:從實(shí)踐到原理,帶你參透 gRPC gRPC 在 Go 語言中大放異彩,越來越多...
TensorFlow Serving是一個開源的高性能機(jī)器學(xué)習(xí)模型部署框架,可用于將訓(xùn)練好的模型部署到生產(chǎn)環(huán)境中進(jìn)行預(yù)測。TensorFlow Serving具有許多有用的功能,如模型版本控制、模型熱更新、模型的灰度發(fā)布和模型可擴(kuò)展性等,這些功能使得TensorFlow Serving成為生產(chǎn)環(huán)境中部署機(jī)器學(xué)習(xí)模型的理想選擇。本文將介紹如何使用TensorFlow Serving進(jìn)行模型部署。 ...
閱讀 2432·2021-11-23 09:51
閱讀 1240·2021-11-22 13:54
閱讀 3468·2021-09-24 10:31
閱讀 1141·2021-08-16 10:46
閱讀 3669·2019-08-30 15:54
閱讀 731·2019-08-30 15:54
閱讀 2916·2019-08-29 17:17
閱讀 3194·2019-08-29 15:08