简体   繁体   English

如何进一步优化(首先是速度,然后是内存)

[英]How to optimize this further (speed first, then memory)

I have this small code that takes an object and convert it to a byte[]. 我有这个小的代码,需要一个对象并将其转换为byte []。 Using C# 4.0. 使用C#4.0。 Can I optimize this further regarding speed then memory usage? 我可以进一步优化速度和内存使用吗? Even small changes would be great - calling this several thousand times+ per second. 即使很小的变化也将是巨大的-每秒调用数千次以上。

    public static byte[] ObjectToByteArray(object obj)
    {
        if (obj == null)
            return null;
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream();

        using (ms)
        {
            bf.Serialize(ms, obj);  
        }

        return ms.ToArray();
    }

If you want to optimize this further, the first thing you need to know is where you are currently spending the most time. 如果您想进一步优化它,那么您首先需要知道的是您目前在哪里花费最多的时间。 Did you run this through a profiler? 您是否通过探查器运行此程序? What were the results? 结果如何?

I would also ask myself "what concrete benefits will optimizing this provide to my users?". 我还会问自己“优化此功能将为用户带来什么具体好处?”。 In other words, am I optimizing this because, as an Engineer, I want to perfect the code or because it will provide a real benefit to the people I'm delivering the solution to? 换句话说,我是否在优化它,是因为作为一名工程师,我想完善代码,还是因为它将为交付解决方案的人员带来真正的好处?

I suspect that you are spending most of your time performing the actual serialization, Changing to a different serializer will likely produce the most benefit. 我怀疑您花了大部分时间执行实际的序列化,更改为其他序列化器可能会产生最大的收益。 See the following question for alternative, faster serializers: 有关替代的,更快的序列化器,请参见以下问题:

Fast and compact object serialization in .NET .NET中快速紧凑的对象序列化

The problem is that BinaryFormatter is using reflection to read the fields of your objects. 问题在于BinaryFormatter使用反射来读取对象的字段。 Assume you have a simple class with 1 field: 假设您有一个包含1个字段的简单类:

[Serializable]
public class Test
{
    public int A;
}

If you serialize an array of those using BinaryFormatter, it will do something like that for each instance of Test: 如果使用BinaryFormatter序列化一个数组,它将对Test的每个实例执行类似的操作:

int val = (int)typeof(Test).GetField("A").GetValue(obj);
var bytes = BitConverter.GetBytes(val);
stream.Write(bytes, 0, bytes.Length);

The calls to GetField() will consume quite a lot of time. 调用GetField()将花费大量时间。 You can significantly improve the speed using 3 ways: 您可以使用3种方法来显着提高速度:

  1. Serialize everything manually. 手动序列化所有内容。 Something similar to this code: 类似于以下代码:

     void SimpleSerialize(Stream stream, Test[] arr) { foreach (var obj in arr) { var bytes = BitConverter.GetBytes(obj.A); stream.Write(bytes, 0, bytes.Length); } } 
  2. Generate a custom serialization class on-the-fly using Reflection.Emit functionality. 使用Reflection.Emit功能即时生成自定义序列化类。 This is more generic and "clean", but requires a lot of effort. 这是更通用且“干净”的方法,但需要付出很多努力。

  3. If you're fine with it, use some third-party serializer that suits your needs. 如果您满意,请使用一些适合您需要的第三方串行器

There's really not much you could do to improve this code. 确实没有什么可以改进此代码的。 If you are dealing with simple objects you could improve this code by replacing the BinaryFormatter with a BinaryWriter and manually serializing each field/property which would be the fastest serialization you could get. 如果要处理简单的对象,则可以通过用BinaryWriter替换BinaryFormatter并手动序列化每个字段/属性来改进此代码,这将是最快的序列化。 But that's an extreme measure you should take only if you have experimentally determined that this code is somehow a bottleneck for your application. 但这是一个极端的措施,只有在实验确定该代码在某种程度上成为应用程序的瓶颈时,才应采取此措施。 Otherwise you might be wasting your time doing micro-optimizations. 否则,您可能会浪费时间进行微优化。

Define a ThreadStatic byte[] as an instance field and use it as a cache. 定义一个ThreadStatic byte[]作为实例字段,并将其用作缓存。 Wrap your memory stream around this cache object. 将您的内存流包装在此缓存对象周围。 When you use MemoryStream as written in your code, you will be performing tons of allocation, re-allocation, and array copying steps, as MemoryStream will be resizable. 当您按代码编写使用MemoryStream ,将执行大量的分配,重新分配和数组复制步骤,因为MemoryStream可以调整大小。 There is also the cost of garbage collection to consider. 还需要考虑垃圾收集的成本。

Possibly, though I'm not sure how well this will work, cache both your formatting objects as ThreadStatic instance fields. 可能的是,尽管我不确定这样做的效果如何,但是将两个格式化对象都缓存为ThreadStatic实例字段。

PS, I'm sure it's a mistake, but notice that you're disposing of the MemoryStream before using it. PS,我确定这是一个错误,但是请注意,在使用MemoryStream之前,请先对其进行处置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM