首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用python更快地循环grpc响应迭代器

如何用python更快地循环grpc响应迭代器
EN

Stack Overflow用户
提问于 2022-02-16 09:33:57
回答 2查看 647关注 0票数 0

我使用python调用一个grpc服务,该服务使用大约100万个迭代器对象进行响应。目前,我正在使用列表理解来访问迭代器所需的1属性:

代码语言:javascript
复制
stub = QueryStub(grpc_channel)
return [object.attribute_i_need for object in stub.ResponseMethod]

访问大约一百万个属性需要一段时间(大约2-3分钟)。有什么办法能让我加快速度吗?想知道人们是如何更快地处理这些场景的。我还尝试使用list(stub.ResponseMethod)[*stub.ResponseMethod]来更快地解压缩或检索对象,但是这些方法花费的时间更长,因为迭代器对象有许多我不需要的其他元数据,并将它们存储起来。

我不一定需要将属性存储在内存中,更快地访问这些属性是我想要实现的

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-02-24 16:32:04

根据这份文件的说法,我想说你需要尝试两件事:

  • 通过执行以下操作来使用异步API (如果还没有这样做的话):
代码语言:javascript
复制
async def run(stub: QueryStub) -> None:
    async for object in stub.ResponseMethod(empty_pb2.Empty()):
        print(object.attribute_i_need)

注意,空()仅仅是因为我不知道您的API定义。

  • 第二种方法是尝试实验特性SingleThreadedUnaryStream (如果适用于您的情况),方法是:
代码语言:javascript
复制
with grpc.insecure_channel(target='localhost:50051', options=[(grpc.experimental.ChannelOptions.SingleThreadedUnaryStream, 1)]) as channel:

我试过的

我不知道它是否涵盖了您的用例(您可以给我更多的信息,我会更新),但是下面是我尝试过的:

我有一个模式,如:

代码语言:javascript
复制
service TestService {
  rpc AMethod(google.protobuf.Empty) returns (stream Test) {} // stream is optional, I tried with both
}

message Test {
  repeated string message = 1;
  repeated string message2 = 2;
  repeated string message3 = 3;
  repeated string message4 = 4;
  repeated string message5 = 5;
  repeated string message6 = 6;
  repeated string message7 = 7;
  repeated string message8 = 8;
  repeated string message9 = 9;
  repeated string message10 = 10;
  repeated string message11 = 11;
}

在服务器端(使用异步),我有

代码语言:javascript
复制
async def AMethod(self, request: empty_pb2.Empty, unused_context) -> AsyncIterable[Test]:
    test = Test()
    for i in range(10):
        test.message.append(randStr())
    # repeat append for every other field or not
    for i in range(1000000):
        yield test

其中randStr创建长度为10000的随机字符串(完全是任意的)。

以及客户端(使用SingleThreadedUnaryStream和异步)

代码语言:javascript
复制
async def run(stub: TesterStub) -> None:
    tests = stub.AMethod(empty_pb2.Empty())

    async for test in tests:
        print(test.message)

基准测试

注意:这可能会因您的机器而异。

对于只填充了一个repeated field的示例,我得到了77 sec的平均值(运行3次)。

对于所有正在填充的字段,它真的很长,所以我尝试提供更小的字符串(10长),但仍然需要太长的时间。我认为repeatedstream的混合不是一个好主意。我也尝试了没有stream,我得到了平均(运行3次)的45 sec

我的结论

如果所有重复的字段都填充了数据,这是非常慢的,当只有一个字段被填充时,这是正常的。,但总的来说,我认为异步对有帮助。

此外,这份文件解释说,Protocol Buffers are not designed to handle large messages,但是Protocol Buffers are great for handling individual messages within a large data set

我建议,如果我正确地理解了您的模式,您将重新考虑API的设计,因为这似乎不是最优的。

但是,再一次,我可能还没有正确理解模式。

票数 1
EN

Stack Overflow用户

发布于 2022-02-24 10:43:06

如果您还没有这样做,我建议您使用for循环遍历对象。但是,需要说明的是:重要的是要认识到,您在循环中放置的所有内容都会在每次循环迭代中执行。优化循环的关键是最小化的操作。即使是看起来非常快的操作,如果重复多次,也要花费很长时间。执行1微秒/百万次的操作需要1秒才能完成。

不要在循环中,甚至在循环开始的情况下,执行像len(list)这样的操作。

示例

代码语言:javascript
复制
a = [i for i in range(1000000)]
length = len(a)
for i in a:
   print(i - length)

代码语言:javascript
复制
a = [i for i in range(1000000)]
for i in a:
   print(i - len(a))

您还可以使用像循环展开(展开)这样的技术,这是一种循环转换技术,它试图以牺牲程序二进制大小为代价优化程序的执行速度,这是一种称为空时权衡的方法。

使用像mapfilter等函数而不是显式的for循环也可以提供一些性能改进。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71139292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档