我们要避免gRPC通信中的数据复制。
我在原始文件中有以下(不是真实的)示例:
message Person
{
string id = 1;
string Name = 2;
string Address = 3;
}
message PersonId
{
required string id = 1;
}
service PersonService
{
rpc GetPersonById( PersonId ) returns Person;
}
它工作正常。但是当我实现它时,我已经将所有数据复制到了请求中:
class PersonServiceImpl : PersonService.MaterialServiceBase
{
public override Task<Person> GetPersonById( PersonId request, ServerCallContext context )
{
Datamodel.Person person = GetPersonForDatabaseAsync(request.Id).Result;
Task.FromResult( new Person() {
Id = person.Id,
Name = person.Name,
Address = person.Address
} );
}
}
但是,当我们避免数据复制时,它很慢,因为当我们向Person添加新成员时,它很慢而且很危险。完美的代码如下:
public override Task<Person> GetPersonById( PersonId request, ServerCallContext context )
{
return GetPersonForDatabaseAsync(request.Id);
}
有可能吗?
我们检查性能,然后将25%的时间用于封送和拆组,特别是在大型类型上,该类型具有嵌套类型,例如“大订单”。
我添加了Java标记,因为它也是Java环境中的相关问题。
由于评论而编辑:
namespace Datamodel
{
class Person
{
string Id { get; set; }
string Name { get; set; }
string Address { get; set; }
}
}
从另一个角度来看,问题是:我应该如何更改Datamodel.Person
以使其与gRPC
响应兼容。
答案 0 :(得分:0)
不幸的是,由于protobuf代码的生成,这是不可能的。所有成员和功能都经过硬编码。
当gRPC允许使用接口而不是直接成员定义为消息类时,这将是很棒的。该接口将包含所有成员和一个create函数。
因此,生成的代码将与此更改:
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom( pb::CodedInputStream input )
{
uint tag;
while ( ( tag = input.ReadTag() ) != 0 )
{
switch ( tag )
{
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom( _unknownFields, input );
break;
case 10:
{
Id = input.ReadString();
break;
}
case 18:
{
Name = input.ReadString();
break;
}
}
}
}
对此:
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom( pb::CodedInputStream input )
{
uint tag;
while ( ( tag = input.ReadTag() ) != 0 )
{
switch ( tag )
{
default:
Instance.UnknownFields = pb::UnknownFieldSet.MergeFieldFrom( Instance.UnknownFields, input );
break;
case 10:
{
Instance.Id = input.ReadString();
break;
}
case 18:
{
Instance.Name = input.ReadString();
break;
}
}
}
}
其中Instance
是从原型文件生成的接口的实现:
public interface IPerson
{
private pb::UnknownFieldSet UnknownFields;
string Id { get; set; }
string Name { get; set; }
}
如果我的Datamodel.Person
实现了该接口,并且生成的Person
消息存储并通过此IPerson
接口检索了数据,那么我们可以避免数据复制以及使用gRPC速度会提高25%。
我认为这是gRPC的巨大优势,也许Jon Skeet可以做到。当我们有明确的概念时,我可以进行c,c ++和c#的更改。
顺便说一句,对于gRPC,这将是一个巨大的进步,因为这是人们使用REST而不是REST的原因之一。在REST世界中,可以使用JSON Datamodel
将数据直接检索到Serialize
结构。他们可以使用Deserialize
直接发送结构。
它必须是protobuf文件中的一个新选项,并且所有巫婆支持的界面都可以使用它。