Эффективная настройка поля сообщения в Python Protobuf

Я использую Protobuf (v3.5.1) в проекте Python, над которым я работаю. Моя ситуация может быть упрощена до следующего:

// 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 источники, но не нашел ничего применимого.

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 объект. Однако, если чья-то проблема заключается во вложенных или повторяющихся полях, это не поможет - такие поля копируются поле за полем. Это имеет смысл - если кто-то копирует сообщение, они хотят, чтобы они были независимыми. В противном случае внесение изменений в исходное сообщение приведет к изменению скопированного (и наоборот).

Если есть что-то похожее на семантику перемещения C++ ( https://github.com/google/protobuf/issues/2791) или set_allocated_...() в Python protobuf, это решило бы это, однако я не знаю о такой возможности.

Другие вопросы по тегам