我在我正在研究的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生成的源代码,但没有找到适用的内容。
答案 0 :(得分:1)
当谈到大string
或bytes
个对象时,似乎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
个对象的问题。但是,如果某人的问题出现在嵌套或重复的字段中,这将无济于事 - 这些字段将逐字段复制。它确实有意义 - 如果复制一条消息,他们希望这两者是独立的。如果不是,则对原始邮件进行更改将修改复制(反之亦然)。
如果在Python protobuf中有类似C ++移动语义(https://github.com/google/protobuf/issues/2791)或set_allocated_...()
的内容,那就可以解决它,但是我不知道这样的功能。