-1

我有这个小代码,它接受一个对象并将其转换为字节 []。使用 C# 4.0。我可以在速度和内存使用方面进一步优化吗?即使是很小的变化也会很棒 - 每秒调用数千次以上。

    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();
    }
4

4 回答 4

3

如果您想进一步优化这一点,您需要知道的第一件事是您目前花费最多的时间。你是通过探查器运行的吗?结果如何?

我还会问自己“优化它会给我的用户带来什么具体的好处?”。换句话说,我优化这个是因为作为一名工程师,我想完善代码还是因为它会给我交付解决方案的人带来真正的好处?

我怀疑您大部分时间都在执行实际的序列化,更改为不同的序列化程序可能会产生最大的好处。请参阅以下问题以获取替代的、更快的序列化程序:

.NET 中快速紧凑的对象序列化

于 2012-06-24T17:43:28.723 回答
2

问题是 BinaryFormatter 使用反射来读取对象的字段。假设您有一个带有 1 个字段的简单类:

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

如果您使用 BinaryFormatter 序列化一个数组,它将为每个 Test 实例执行类似的操作:

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

对 GetField() 的调用将消耗大量时间。您可以使用 3 种方式显着提高速度:

  1. 手动序列化所有内容。类似于此代码的内容:

    void SimpleSerialize(Stream stream, Test[] arr)
    {
        foreach (var obj in arr)
        {
            var bytes = BitConverter.GetBytes(obj.A);
            stream.Write(bytes, 0, bytes.Length);
        }
    }
    
  2. 使用 Reflection.Emit 功能即时生成自定义序列化类。这更通用和“干净”,但需要付出很多努力。

  3. 如果您对此感到满意,请使用一些适合您需求的第三方序列化程序。

于 2012-06-24T19:28:56.317 回答
1

您确实无法改进此代码。如果您正在处理简单的对象,您可以通过用BinaryFormattera替换BinaryWriter并手动序列化每个字段/属性来改进此代码,这将是您可以获得的最快序列化。但是,只有当您通过实验确定此代码在某种程度上是您的应用程序的瓶颈时,您才应该采取这种极端措施。否则,您可能会浪费时间进行微优化。

于 2012-06-24T17:42:44.557 回答
0

将ThreadStatic 定义byte[]为实例字段并将其用作缓存。将你的内存流包裹在这个缓存对象周围。当您MemoryStream按照代码中所写的方式使用时,您将执行大量分配、重新分配和数组复制步骤,并且MemoryStream可以调整大小。还需要考虑垃圾收集的成本。

可能,虽然我不确定这将如何工作,但将您的格式化对象缓存为ThreadStatic实例字段。

PS,我确定这是一个错误,但请注意,您MemoryStream在使用它之前将其丢弃。

于 2012-06-24T19:13:50.513 回答