python grpc 异步调用使用记录

20 篇文章 0 订阅
14 篇文章 4 订阅
protobuf
syntax = "proto3";
option go_package = "./;proto";

service StreamRpc{
  rpc GetServerResult(Requests) returns (Reply);
  rpc GetServerStream(Requests) returns (stream Reply);
  rpc ClientSendStream(stream Requests) returns (Reply);
  rpc ServerClientStream(stream Requests) returns (stream Reply);
}

message Requests {
  string data = 1;
}

message Reply{
  string result = 1;
}
server
import asyncio
import time

import grpc

from rpc.async_grpc_stream.proto import stream_data_pb2, stream_data_pb2_grpc


class AsyncStreamServer(stream_data_pb2_grpc.StreamRpcServicer):
    # 一元调用
    async def GetServerResult(self, request, context):
        print("GetServerResult 服务器接收到的数据是: ", request.data)
        return stream_data_pb2.Reply(result="hell tnan")

    # 服务器发送流式数据给客户端
    async def GetServerStream(self, request, context):
        print("GetServerStream 服务器接收到的数据是: ", request.data)
        for i in range(10):
            # 通过context rpc上下文 来异步发送流数据
            await context.write(stream_data_pb2.Reply(result="{}".format(i)))

    # 服务器接收客户端流式数据
    async def ClientSendStream(self, request_iterator, context):
        async for i in request_iterator:
            print(i)
            await asyncio.sleep(1)
        print("结束: ", time.time())
        return stream_data_pb2.Reply(result="aabbbbbb")

    # 服务端发送stream数据协程
    async def ServerSendStreamClient(self, context):
        for i in range(5):
            print("服务器正在往客户端流式发送数据: ", i)
            await context.write(stream_data_pb2.Reply(result="{}".format(i)))
            await asyncio.sleep(1)

    # 服务器接收客户端stream 数据协程
    async def RecvClientStream(self, request_iterator):
        async for i in request_iterator:
            print("服务器接收到客户端流式数据: ", i)
        print("数据接收结束")

    # 双向流
    async def ServerClientStream(self, request_iterator, context):
        # 添加两个协程任务,等待协程任务执行完毕
        await asyncio.gather(
            self.ServerSendStreamClient(context),
            self.RecvClientStream(request_iterator)
        )


async def main():
    # 创建grpc 异步服务器
    g = grpc.aio.server()
    g.add_insecure_port("0.0.0.0:8659")
    stream_data_pb2_grpc.add_StreamRpcServicer_to_server(AsyncStreamServer(), g)
    await g.start()
    await g.wait_for_termination()


if __name__ == '__main__':
    asyncio.run(main())

client
import asyncio
import time

import grpc

from rpc.async_grpc_stream.proto import stream_data_pb2, stream_data_pb2_grpc


class ClientStream:

    def __init__(self):
        self.channel = grpc.aio.insecure_channel("127.0.0.1:8659")
        self.sub = stream_data_pb2_grpc.StreamRpcStub(channel=self.channel)

    async def GetServerResult(self):
        # 异步调用rpc
        result = await self.sub.GetServerResult(stream_data_pb2.Requests(data="aaa"))
        print("GetServerResult result: ", result)

    # 单向流
    async def GetServerStream(self):
        # 获取单向流对象
        stream_client = self.sub.GetServerStream(stream_data_pb2.Requests(data="aaa"))
        # 通过异步for 循环获取响应数据
        async for i in stream_client:
            print("GetServerStream result : ", i)

    # 单向流
    async def ClientSendStream(self):
        # 获取单向流对象
        stream_client = self.sub.ClientSendStream()
        for i in range(10):
            await stream_client.write(stream_data_pb2.Requests(data="{}".format(i)))
        # 客户端使用异步发送流数据需要手动关闭,客户端使用同步调用发送流数据的时候是不需要手动关闭的:
        # 同步调用代码如下:
        # def Client_send_stream(self):
        #     index = 0
        #     while 1:
        #         index += 1
        #         yield stream_data_pb2.Requests(data="{}".format(index))
        #         # time.sleep(1)
        #         if index == 10:
        #             break
        #     print("已结束")
        # result = self.stub.ClientSendStream(Client_send_stream())

        # 个人猜测是因为同步调用是通过另一个函数方法通过yield生成发送数据,当这个yield生成发送数据方法结束后在
        # ClientSendStream中封装了 自动关闭的功能, 因为同步调用执行完 result 这行代码就可以关闭这次调用了
        # 而异步调用是不会堵塞的, 就意味着,无法在 stream_client = self.sub.ClientSendStream() 期间进行封装
        # 关闭功能,如果在 stream_client 这个流对象生命期间封装 关闭功能的话, 这个ClientSendStream方法在发送完流数据后
        # 可能会做一下其他的事情, 如: 我在发送完流数据后做一些耗时的扫尾工作,导致这次的rpc调用迟迟无法结束,这会占用服务器
        # 的资源,所以,在 stream_client 生命周期做关闭功能封装也是不现实的,所以就需要我们手动关闭

        await stream_client.done_writing()
        data = await stream_client
        print("ClientSendStream result: ", data)

    # 双向流客户端往服务器发送流数据
    async def ClientSendStreamServer(self, stream_client):
        for i in range(6):
            print("正在往服务器发送流式数据: ", i, time.time())
            await stream_client.write(stream_data_pb2.Requests(data="send data {}".format(i)))
            await asyncio.sleep(2)
        await stream_client.done_writing()

    # 双向流 接收服务器发送的流数据
    async def RecvServerStream(self, stream_client):
        async for i in stream_client:
            print("接收到服务器流式数据: ", i)
        print("数据接收结束", time.time())

    # 双向流
    async def ServerClientStream(self):
        stream_client = self.sub.ServerClientStream()
        # 将 接收流、发送流 方法添加到事件循环中, 等待这两个方法结束
        await asyncio.gather(
            self.ClientSendStreamServer(stream_client),
            self.RecvServerStream(stream_client)
        )


async def main():
    client_stream = ClientStream()
    await client_stream.ClientSendStream()


if __name__ == '__main__':
    client_stream = ClientStream()
    asyncio.run(main())

查看grpc 异步方法

可以在grpc.aio 包中查看grpc提供的异步方法
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值