我有以下代码将List序列化为字节数组,以便通过Web Services进行传输。代码在较小的实体上运行相对较快,但这是一个包含60,000个左右项目的列表。执行formatter.Serialize方法需要几秒钟。无论如何要加速这个?
public static byte[] ToBinary(Object objToBinary)
{
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
formatter.Serialize(memStream, objToBinary);
memStream.Seek(0, SeekOrigin.Begin);
return memStream.ToArray();
}
}
答案 0 :(得分:4)
您遇到的效率低下来自多个来源:
ToArray
(如Danny所说)。通过对ISerializable
中包含的对象类型实施List
,您可以获得相当大的改进。这将删除使用反射的默认序列化行为。
如果减少包含序列化数据的关联数组中的元素数量,则可以获得更快的速度。确保您在该关联数组中存储的元素是基本类型。
最后,你可以消除ToArray
但我怀疑你甚至会注意到给你带来的撞击。
答案 1 :(得分:3)
如果您想要一些真正的序列化速度,请考虑使用protobuf-net这是google协议缓冲区的c#版本。它应该是order of magnitude faster二进制格式化程序。
答案 2 :(得分:1)
将一个镜头中60,000个项目的整个数组(或集合)序列化为单个大型byte []数组,而不是单独的块,可能要快得多。让每个单独的对象都由它自己的byte []数组表示您正在使用的系统的其他部分的要求吗?是否已知对象的实际类型?如果您使用特定的Type(可能是所有这些60,000个对象的一些公共基类),那么框架就不必执行那么多的转换和搜索预构建的序列化程序集。现在你只给它Object。
答案 3 :(得分:1)
.ToArray()创建一个新数组,使用不安全的方法将数据复制到现有数组更有效(例如使用fixed访问流的内存,然后使用MemCopy()通过DllImport复制内存)。
还要考虑使用更快的自定义格式化程序。
答案 4 :(得分:0)
我启动了一个代码生成器项目,其中包含二进制文件DataContract
-Serialzer that beats at least Json.NET by a factor of 30。您所需要的只是the generator nuget package和additional lib,它可以更快地替换BitConverter
。
然后,您创建一个分部类,并使用DataContract
和每个可序列化属性DataMember
进行装饰。然后,生成器将创建一个ToBytes
- 方法,并且可以与附加的lib一起序列化集合。从this post看看我的例子:
var objects = new List<Td>();
for (int i = 0; i < 1000; i++)
{
var obj = new Td
{
Message = "Hello my friend",
Code = "Some code that can be put here",
StartDate = DateTime.Now.AddDays(-7),
EndDate = DateTime.Now.AddDays(2),
Cts = new List<Ct>(),
Tes = new List<Te>()
};
for (int j = 0; j < 10; j++)
{
obj.Cts.Add(new Ct { Foo = i * j });
obj.Tes.Add(new Te { Bar = i + j });
}
objects.Add(obj);
}
使用此生成的ToBytes()
方法:
public int Size
{
get
{
var size = 24;
// Add size for collections and strings
size += Cts == null ? 0 : Cts.Count * 4;
size += Tes == null ? 0 : Tes.Count * 4;
size += Code == null ? 0 : Code.Length;
size += Message == null ? 0 : Message.Length;
return size;
}
}
public byte[] ToBytes(byte[] bytes, ref int index)
{
if (index + Size > bytes.Length)
throw new ArgumentOutOfRangeException("index", "Object does not fit in array");
// Convert Cts
// Two bytes length information for each dimension
GeneratorByteConverter.Include((ushort)(Cts == null ? 0 : Cts.Count), bytes, ref index);
if (Cts != null)
{
for(var i = 0; i < Cts.Count; i++)
{
var value = Cts[i];
value.ToBytes(bytes, ref index);
}
}
// Convert Tes
// Two bytes length information for each dimension
GeneratorByteConverter.Include((ushort)(Tes == null ? 0 : Tes.Count), bytes, ref index);
if (Tes != null)
{
for(var i = 0; i < Tes.Count; i++)
{
var value = Tes[i];
value.ToBytes(bytes, ref index);
}
}
// Convert Code
GeneratorByteConverter.Include(Code, bytes, ref index);
// Convert Message
GeneratorByteConverter.Include(Message, bytes, ref index);
// Convert StartDate
GeneratorByteConverter.Include(StartDate.ToBinary(), bytes, ref index);
// Convert EndDate
GeneratorByteConverter.Include(EndDate.ToBinary(), bytes, ref index);
return bytes;
}
它在~1.5微秒内将每个物体序列化 - &gt; 1,7ms 中的1000个对象。