Efficiently reading/writing multiple messages in C++

1,938 views
Skip to first unread message

Evan Jones

unread,
Jun 17, 2010, 5:05:33 PM6/17/10
to Protocol Buffers
Is the intention of the C++ CodedStreams that they are "cheap" and so
I should use one per message? Or should I reuse one if I have a large
sequence of messages to read/write? For writing, I've been using a
single CodedOutputStream, something like:

CodedOutputStream out(...)
for (message in long sequence) {
out.WriteVarint32((int32_t) message.ByteSize());
message.SerializeToCodedStream(&out);
}

This works fine. However, doing the same on input does not work,
because I run into the total byte limit. In Java, I call
resetSizeCounter() to avoid this problem. Is there a reason a similar
function does not exist for the C++ side? I'm working around this by
moving the CodedInputStream inside my loop, which is fine, but seems
sub-optimal. At the very least, since I have lots of small messages,
this means my ZeroCopyInputStream's methods get called many times.


Related question: If I am writing length-prefixed values, what is the
"best" way to do this? I think there are 3 approaches:

1. out.WriteVarint32(msg.ByteSize()); msg.SerializeToCodedStream(&out);

This approach will choose between the "ToArray" and "regular" versions
of the Serialize method, as appropriate. However, it computes the
ByteSize twice.

2. out.WriteVarint32(msg.ByteSize());
msg.SerializeWithCachedSizes(&out);

This computes the ByteSize once, but never uses the "fast path"
ToArray method.

3. Some custom code that calls ByteSize once, then chooses between the
"fast" and "slow" methods, as appropriate. Is there actually any
significant difference in performance between SerializeWithCachedSizes
and SerializeWithCachedSizesToArray, so it would be worth me actually
doing this?

Thanks,

Evan

--
Evan Jones
http://evanjones.ca/

Evan Jones

unread,
Jun 17, 2010, 5:10:48 PM6/17/10
to Protocol Buffers
On Jun 17, 2010, at 17:05 , Evan Jones wrote:
> I'm working around this by moving the CodedInputStream inside my
> loop, which is fine, but seems sub-optimal. At the very least, since
> I have lots of small messages, this means my ZeroCopyInputStream's
> methods get called many times.

Based on previous mailing list discussions, this is the recommend way
to do this. I don't care enough at the moment to test it, but it seems
like using a single CodedInputStream for many small messages would be
more efficient. Maybe at some point I'll try some benchmarks, but for
now I'll ignore this.

Kenton Varda

unread,
Jun 18, 2010, 5:06:33 PM6/18/10
to Evan Jones, Protocol Buffers
You could reconstruct the stream every N bytes, where N << limit.

But I doubt there is really much overhead in constructing a new CodedInputStream on the stack for each message.  No heap space is allocated in the process.

I'd also be amenable to a method which resets the bytes counter.

What we really need is a MessageStream class which handles this kind of stuff at a higher level, but I haven't gotten around to writing such a thing.

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To post to this group, send email to prot...@googlegroups.com.
To unsubscribe from this group, send email to protobuf+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/protobuf?hl=en.


Evan Jones

unread,
Jun 19, 2010, 12:17:25 PM6/19/10
to Kenton Varda, Protocol Buffers
On Jun 18, 2010, at 17:06 , Kenton Varda wrote:
> But I doubt there is really much overhead in constructing a new
> CodedInputStream on the stack for each message. No heap space is
> allocated in the process.

If I end up doing some performance intensive stuff with this code,
I'll look into it at some point and report back. For now, what I'm
doing is plenty fast enough. I was mostly just slightly surprised that
I can't do what I do on the Java side.

> What we really need is a MessageStream class which handles this kind
> of stuff at a higher level, but I haven't gotten around to writing
> such a thing.


Huh. Probably like most people on this list, I have bits and pieces of
protocol buffer related "support" code lying around. One of the pieces
is something that is like a "MessageStream." It may be a bit too
specific for my application at the moment, but I certainly wouldn't be
opposed to putting some effort into including it in protobuf, or in a
protobuf-utils type project.

Hochhaus, Andrew

unread,
Jun 26, 2013, 11:17:19 AM6/26/13
to Evan Jones, Protocol Buffers
Does anyone have any insight on Evan's "related question" below?

On Thu, Jun 17, 2010 at 5:05 PM, Evan Jones <ev...@mit.edu> wrote:
> Related question: If I am writing length-prefixed values, what is the "best"
> way to do this? I think there are 3 approaches:
>
> 1. out.WriteVarint32(msg.ByteSize()); msg.SerializeToCodedStream(&out);
>
> This approach will choose between the "ToArray" and "regular" versions of
> the Serialize method, as appropriate. However, it computes the ByteSize
> twice.
>
> 2. out.WriteVarint32(msg.ByteSize()); msg.SerializeWithCachedSizes(&out);
>
> This computes the ByteSize once, but never uses the "fast path" ToArray
> method.
>
> 3. Some custom code that calls ByteSize once, then chooses between the
> "fast" and "slow" methods, as appropriate. Is there actually any significant
> difference in performance between SerializeWithCachedSizes and
> SerializeWithCachedSizesToArray, so it would be worth me actually doing
> this?

-Andy

Feng Xiao

unread,
Jun 27, 2013, 12:56:51 PM6/27/13
to Hochhaus, Andrew, Evan Jones, Protocol Buffers
The fast path only works if the "optimize_for" option is set to "SPEED" in the proto file. If that's not the case, just use approach 2.
If you enabled the "optimize_for" option and want to take advantage of the fast path, 3) seems to be a reasonable approach. The code should be similar to the implementation of WireFormatLite::WriteMessageMaybeToArray(). Maybe we can just add a WireFormatLite::WriteMessageNoTagMaybeToArray().

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+u...@googlegroups.com.

To post to this group, send email to prot...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages