Speed up deserialization

A

Adam Benson

Hi,

We sometimes have to send large numbers (about 4000) of small items from
client to server and back again.

We manually serialize and deserialize using BinaryFormatter and profiling
shows two things:

1) Using a SerializationInfoEnumerator in the deserialization constructor is
much faster than specifically reading each field.

i.e. this pattern

SerializationInfoEnumerator sie = info.GetEnumerator();

while (sie.MoveNext())
{
o = sie.Current.Value;
objname = sie.Current.Name;

switch (objname)
{
case "B1": tooltip = (string)o;
break;
case "B2": clipTypeColour = Color.FromArgb((int)o);
break;
...
}
}

is much faster than this

this.tooltip = info.GetString("B1");
this.clipTypeColour = info.Get .... etc etc

2) ObjectReader.Deserialize seems to spend 1/4 of its time in DoFixups,
which ends up calling our deserialization constructors. But 3/4 of its time
is spent in Run. My guess is that Run builds a map of all that's available
including a map of names to objects.

So, my question is, is it possible to call BinaryFormatter.Deserialize in
such a way that it does not build a map of object names to values on the
grounds that we will just enumerate through it all using a
SerializationInfoEnumerator? I suspect if we could do that we would see a
huge leap in performance.

Of course, it may not be possible, and my question may reflect my ignorance
of what's really going on.

Thanks for any info,

- Adam.

==============================
(e-mail address removed)
 
M

Marc Gravell

I would suspect that "Run" is necessary to prepare (split etc) the
data that then happens to be conveniently enumerated, so I doubt you
can remove this.

However; if the data is relatively simple (i.e. not a cyclic object
graph), have you considered simpler serializers?

I'm biased (as the author), but protobuf-net (free) can out-perform
BinaryFormatter for both speed and bandwidth in most scenarios (but it
doesn't include type metadata in the stream; an economy but also
sometimes a niggle) - and if you really want can be injected into
existing remoting code (I'm assuming you are using remoting) very
simply:

protected MyType(SerializationInfo info, StreamingContext
context)
: this()
{
Serializer.Merge(info, this);
}
void ISerializable.GetObjectData(SerializationInfo info,
StreamingContext context)
{
Serializer.Serialize(info, this);
}

with markers on the type reminiscent of WCF:

[ProtoContract]
public class MyType {
[ProtoMember(1)]
public string ToolTip {get;set;}

public Color Color {get;set;} // not used in serialization

[ProtoMember(2)]
private int ColorArgb { ... conversions to/from
this.Color ... }
}

(actually it accepts WCF [DataMember] markers too, as long as the
Order property provides a unique tag per member)

Marc Gravell
protobuf-net author and C# MVP
 
M

Marc Gravell

(I should add; if you *aren't* using remoting, then you can just read-
from/write-to a stream)
 
A

Adam Benson

Thanks, Marc.

You are correct we are using remoting.

I must admit I'd hoped there was a "Don'tGoQuiteSoSlowly" property we could
just set to false!

But I appreciate your suggestion of trying a different serializer. I may
well give it a spin ... if the boss wants to spend the time on it.

Cheers,

Adam.
==========
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top