我使用python调用一个grpc服务,该服务使用大约100万个迭代器对象进行响应。目前,我正在使用列表理解来访问迭代器所需的1属性:
stub = QueryStub(grpc_channel)
return [object.attribute_i_need for object in stub.ResponseMethod]访问大约一百万个属性需要一段时间(大约2-3分钟)。有什么办法能让我加快速度吗?想知道人们是如何更快地处理这些场景的。我还尝试使用list(stub.ResponseMethod)和[*stub.ResponseMethod]来更快地解压缩或检索对象,但是这些方法花费的时间更长,因为迭代器对象有许多我不需要的其他元数据,并将它们存储起来。
我不一定需要将属性存储在内存中,更快地访问这些属性是我想要实现的
发布于 2022-02-24 16:32:04
根据这份文件的说法,我想说你需要尝试两件事:
async def run(stub: QueryStub) -> None:
async for object in stub.ResponseMethod(empty_pb2.Empty()):
print(object.attribute_i_need)注意,空()仅仅是因为我不知道您的API定义。
SingleThreadedUnaryStream (如果适用于您的情况),方法是:with grpc.insecure_channel(target='localhost:50051', options=[(grpc.experimental.ChannelOptions.SingleThreadedUnaryStream, 1)]) as channel:我试过的
我不知道它是否涵盖了您的用例(您可以给我更多的信息,我会更新),但是下面是我尝试过的:
我有一个模式,如:
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;
}在服务器端(使用异步),我有
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和异步)
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长),但仍然需要太长的时间。我认为repeated和stream的混合不是一个好主意。我也尝试了没有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的设计,因为这似乎不是最优的。
但是,再一次,我可能还没有正确理解模式。
发布于 2022-02-24 10:43:06
如果您还没有这样做,我建议您使用for循环遍历对象。但是,需要说明的是:重要的是要认识到,您在循环中放置的所有内容都会在每次循环迭代中执行。优化循环的关键是最小化的操作。即使是看起来非常快的操作,如果重复多次,也要花费很长时间。执行1微秒/百万次的操作需要1秒才能完成。
不要在循环中,甚至在循环开始的情况下,执行像len(list)这样的操作。
示例
a = [i for i in range(1000000)]
length = len(a)
for i in a:
print(i - length)比
a = [i for i in range(1000000)]
for i in a:
print(i - len(a))您还可以使用像循环展开(展开)这样的技术,这是一种循环转换技术,它试图以牺牲程序二进制大小为代价优化程序的执行速度,这是一种称为空时权衡的方法。
使用像map、filter等函数而不是显式的for循环也可以提供一些性能改进。
https://stackoverflow.com/questions/71139292
复制相似问题