• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

python实现GRPC服务,python实现的grpc通信

武飞扬头像
尚拙谨言
帮助1

grpc是一种基于某种协议实现不同机器间进行通信的服务框架。不同机器可以是不同的服务端、客户端,当服务端实现好某些功能后,提供一个服务接口,供不同客户端进行接口调用,从而让不同客户端都能够“享用”到服务端提供的功能。

在实际业务场景,比如我是做算法的,那么当我的模型训练完成后,要放到线上让别人调用,则经常是以grpc的方式进行实现的。简单流程就是我写个服务端,实现接收客户端传来的数据,并进行模型推理计算,计算结果再返回客户端,那么客户端实际只需要提供数据即可得到它们想要的结果,中间数据的处理过程均由服务端来完成,因此,它还是很方便的有木有~

目录

1. 定义protobuf文件

2. 服务端实现

2. 客户端实现

3. 总结


本文将简单介绍一下如何使用Python来实现一个简单的grpc服务。由于涉及到数据的传输,因此必然涉及到数据格式化问题,就是需要有一种通用的协议将数据格式化,方便在不同机器间都能够高效传输。grpc这里用protobuf(Protocol Buffers)作为通信协议,它是一种高效便捷的数据存储格式,与平台和编程语言无关,因此,只要定义好protobuf协议,用Python也好用Java也好,都可以相互通信,十分方便。

1. 定义protobuf文件

创建一个空白的proto文件,添加以下内容:

  1.  
    // 这里我们用的是proto3版本,版本号是一定要指定的哦!
  2.  
    syntax = "proto3";
  3.  
     
  4.  
    import "谷歌/protobuf/wrappers.proto";
  5.  
     
  6.  
    //这是供java端调用时用到的,咱们python的不用管
  7.  
    //option java_package = "xx.xx.core.grpc.lib.label";
  8.  
    //option java_multiple_files = true;
  9.  
     
  10.  
    //package label;
  11.  
     
  12.  
    service LabelService {
  13.  
    /**
  14.  
    样本集接口
  15.  
    */
  16.  
    rpc receiveSample(SampleRequestList) returns (谷歌.protobuf.BoolValue) {}
  17.  
    }
  18.  
    message SampleRequestList {
  19.  
    repeated SampleRequest reqList = 1;
  20.  
    }
  21.  
     
  22.  
    message SampleRequest {
  23.  
    /**
  24.  
    标签值
  25.  
    */
  26.  
    string labelValue = 1;
  27.  
    /**
  28.  
    样本集数据
  29.  
    */
  30.  
    string text = 2;
  31.  
    }
学新通

我们定义一个简单的接收数据的服务,客户端传labelValue和text数据,服务端接收数据并进行清洗和分词,我们可以打印出来看结果。数据接收成功后向客户端返回BoolValue类型的响应,true或false。

文件定义好后,我们进入到proto文件所在目录,执行

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

执行以上脚本后,会在grpc_file文件夹下生成两个.py文件:

学新通

2. 服务端实现

我们实现一个服务端,用于接收客户端发来的请求,并将接收到的数据进行清洗、分词等处理,请求格式为List,在proto文件中用repeated关键词修饰。

新建python文件,命名receive.py,编写以下内容:

  1.  
    import logging
  2.  
    import sys
  3.  
     
  4.  
    sys.path.append('..')
  5.  
    import time
  6.  
    import datetime
  7.  
    from concurrent import futures
  8.  
     
  9.  
    import grpc_file
  10.  
    import jieba
  11.  
    import re
  12.  
    import grpc
  13.  
     
  14.  
    from grpc_file import ReceiveData_pb2_grpc
  15.  
    # 这个地方的BoolValue可能会飘红,不用管,用就行了
  16.  
    from 谷歌.protobuf.wrappers_pb2 import BoolValue
  17.  
     
  18.  
    jieba.setLogLevel(log_level=0)
  19.  
    pattern = re.compile('(?:https?|ftp|file)://[-A-Za-z0-9 &@#/%?=~_|!:,.;] [-A-Za-z0-9 &@#/%=~_|]')
  20.  
    logger = logging.getLogger('logger')
  21.  
    # 设置日志等级_
  22.  
    logger.setLevel(logging.INFO)
  23.  
     
  24.  
     
  25.  
    class ReceiveDataServer:
  26.  
    def __init__(self, host, port):
  27.  
    self.host = host
  28.  
    self.port = port
  29.  
     
  30.  
    def match_url(self, text):
  31.  
    """
  32.  
    去除url
  33.  
    :param text:
  34.  
    :return:
  35.  
    """
  36.  
    clear = pattern.sub('', text)
  37.  
    return clear
  38.  
     
  39.  
    def seg_sentence(self, data):
  40.  
    """
  41.  
    分词
  42.  
    :param data:
  43.  
    :return:
  44.  
    """
  45.  
    data = self.match_url(data)
  46.  
    seg_text = jieba.cut(data.replace('\t', '').replace('\n', '').replace(' ', ''))
  47.  
    context = ' '.join(seg_text)
  48.  
    return context
  49.  
     
  50.  
    def receiveSample(self, request, context):
  51.  
    """
  52.  
    接收数据的grpc服务接口,该函数的名称要和proto文件中定义的接口名保持一致
  53.  
    :param request:
  54.  
    :param context:
  55.  
    :return:
  56.  
    """
  57.  
    requestlist = request.reqList
  58.  
    try:
  59.  
    for item in requestlist:
  60.  
    text = item.text.replace('\n', '。').replace('\r', '。')
  61.  
    text = self.seg_sentence(text)
  62.  
    print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'),
  63.  
    '*** 添加标签:{},添加文本:{}... ***'.format(item.labelValue, text[:10]))
  64.  
    return BoolValue(value=True)
  65.  
    except:
  66.  
    return BoolValue(value=False)
  67.  
     
  68.  
     
  69.  
    def serve(host, port):
  70.  
    # 启动 rpc 服务
  71.  
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=8))
  72.  
    ReceiveData_pb2_grpc.add_LabelServiceServicer_to_server(ReceiveDataServer(host, port), server)
  73.  
    server.add_insecure_port('{}:{}'.format(host, port))
  74.  
    server.start()
  75.  
    print('Grpc server connect successful!')
  76.  
     
  77.  
    try:
  78.  
    while True:
  79.  
    time.sleep(600)
  80.  
    print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'))
  81.  
    except KeyboardInterrupt:
  82.  
    print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'))
  83.  
    server.stop(0)
  84.  
     
  85.  
     
  86.  
    if __name__ == '__main__':
  87.  
    # host和port写上服务端运行的机器ip和端口;
  88.  
    serve(host='172.xxx.xxx.xxx', port=50001)
学新通

 我们运行一下这个py:

python receive.py

只要ip地址正确,发现服务启动成功!

学新通

2. 客户端实现

启动Server.py,我们再实现一个客户端,命名为client.py,让它能够连接服务端并发送数据:

  1.  
    import sys
  2.  
     
  3.  
    sys.path.append('..')
  4.  
    import grpc
  5.  
    from grpc_file import ReceiveData_pb2, ReceiveData_pb2_grpc
  6.  
     
  7.  
     
  8.  
    def run():
  9.  
    # 连接 rpc 服务器,ip和端口号必须和服务端设置的一致
  10.  
    channel = grpc.insecure_channel('192.xxx.xxx.xx:50001')
  11.  
    # 调用 rpc 服务
  12.  
    stub = ReceiveData_pb2_grpc.LabelServiceStub(channel)
  13.  
    requestlist = ReceiveData_pb2.SampleRequestList()
  14.  
    for data in range(10):
  15.  
    label = str(data)
  16.  
    text = '第{}个标签的数据'.format(label)
  17.  
    # 由于我们在proto文件中定义的接收数据格式为List,所以这里我们需要先定义一个向List中添加数据的对象
  18.  
    request = requestlist.reqList.add()
  19.  
    request.labelValue = label
  20.  
    request.text = text
  21.  
    response = stub.receiveSample(requestlist)
  22.  
    print(response)
  23.  
     
  24.  
    if __name__ == '__main__':
  25.  
    run()
学新通

我们再运行一下客户端:

python client.py

数据发送给服务端成功!

学新通

 当服务端成功接收数据后,会返回给客户端一个 value: true。现在我们再来看下服务端有什么反应,切换回刚才启服务端所在的终端界面:

学新通

 从我们打印的日志中可以看出,服务端成功接收来自客户端发送的数据,而且我们可以看到添加文本后的字符串,已经进行了分词处理,这里为了演示,所以没加入url验证,且只取了前10个字符展示。其实大家可以根据自己的需求,从客户端接收数据后,在服务端代码里添加自己的业务逻辑,实现自己的业务需求,甚至可以做一系列处理后,将数据返回给客户端,只要定义好proto文件的返回值和返回格式即可。例如我们服务端的算法模型接收客户端数据,并对数据进行标签预测和打分,最后将标签和分数返回给客户端,那么proto中相应位置的定义可以如下:

  1.  
    syntax = "proto3";
  2.  
     
  3.  
    service Predict {
  4.  
    rpc predict(LabelRequest) returns (ResultReply) {}
  5.  
    }
  6.  
     
  7.  
    message LabelRequest {
  8.  
    string text = 1;
  9.  
    }
  10.  
     
  11.  
    message ResultReply {
  12.  
    string label = 1;
  13.  
    string score = 2;
  14.  
    }

在服务端中,接口函数应当做如下返回:

return PredictServer_pb2.ResultReply(label=str(labels), score=str(probs))

在客户端中,应当做如下请求与接收相应:

  1.  
    response = stub.predict(PredictServer_pb2.LabelRequest(text='我热爱自然语言处理算法'))
  2.  
    print("预测类别:{}, 预测得分:{}: ".format(response.label, response.score))

3. 总结

通常我们利用grpc来接收不同客户端的请求,并将请求数据做业务逻辑处理,最后再返回给客户端。就好像通信基站一样,接收四面八方传来的手机通信请求,基站将这些请求做相应的处理,再返回给不同客户端,达到互联的目的。

总的来说,python实现简单的grpc需要以下步骤:定义protobuf——>通过protobuf生成2份方法文件——>定义服务端——>定义客户端。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfckcjf
系列文章
更多 icon
同类精品
更多 icon
继续加载