Python Protobuf中的有效消息字段设置



我在正在进行的Python项目中使用Protobuf(v3.5.1(。我的情况可以简化为以下内容:

// Proto file
syntax = "proto3";
message Foo {
    Bar bar = 1;
}
message Bar {
    bytes lotta_bytes_here = 1;
}
# Python excerpt
def MakeFooUsingBar(bar):
    foo = Foo()
    foo.bar.CopyFrom(bar)

我担心.CopyFrom()的内存性能(如果我正确,它是复制内容,而不是参考(。现在,在C 中,我可以使用以下内容:

Foo foo;
Bar* bar = new Bar();
bar->set_lotta_bytes_here("abcd");
foo.set_allocated_bar(bar);

看起来它不需要复制以生成的来源来判断的任何内容:

inline void Foo::set_allocated_bar(::Bar* bar) {
  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
  if (message_arena == NULL) {
    delete bar_;
  }
  if (bar) {
    ::google::protobuf::Arena* submessage_arena = NULL;
    if (message_arena != submessage_arena) {
      bar = ::google::protobuf::internal::GetOwnedMessage(
          message_arena, bar, submessage_arena);
    }
  } else {
  }
  bar_ = bar;
  // @@protoc_insertion_point(field_set_allocated:Foo.bar)
}

python中有类似的东西吗?我已经浏览了Python生成的来源,但没有发现任何适用。

当涉及大型stringbytes对象时,Protobuf似乎可以很好地发现情况。以下通过,这意味着,当创建一个新的Bar对象时,二进制数组是通过参考复制的(Python bytes是不可变的,所以这是有道理的(:

def test_copy_from_with_large_bytes_field(self):
    bar = Bar()
    bar.val = b'12345'
    foo = Foo()
    foo.bar.CopyFrom(bar)
    self.assertIsNot(bar, foo.bar)
    self.assertIs(bar.val, foo.bar.val)

这解决了我的大型bytes对象的问题。但是,如果某人的问题在于嵌套或重复的字段,这将无济于事 - 此类字段是按字段复制的。这确实是有道理的 - 如果一个复制消息,他们希望两者独立。如果不是,则对原始消息进行更改将修改复制(反之亦然(。

如果与C 移动语义类似(https://github.com/google/protobuf/issues/2791(或python Protobuf中的set_allocated_...()可以解决它,但是我不知道此功能是否不知道此类功能,但是。

最新更新