0

我正在使用BinaryFormatter序列化一个相当简单的多维浮点数组,尽管我怀疑任何原始类型都会出现问题。我的多维数组包含 10000x16 个浮点数(160k),并且在我的 PC 上以 ~8 MB/s 的速度进行序列化(60 秒基准写入 ~500 MB 到 SSD 驱动器)。代码:

        Stopwatch stopwatch = new Stopwatch();

        float[,] data = new float[10000 , 16];  // Two-dimensional array of 160,000 floats.
        // OR
        float[]  data = new float[10000 * 16];  // One-dimensional array of 160,000 floats.

        var formatter = new BinaryFormatter();
        var stream = new FileStream("C:\\Temp\\test_serialization.data", FileMode.Create, FileAccess.Write);

        // Serialize to disk the array 1000 times.
        stopwatch.Reset();
        stopwatch.Start();
        for (int i = 0; i < 1000; i++)
        {
            formatter.Serialize(stream, data);
        }
        stream.Close();
        stopwatch.Stop();

        TimeSpan ts = stopwatch.Elapsed;

        // Format and display the TimeSpan value.
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:000}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds);
        Console.WriteLine("Runtime " + elapsedTime);
        var info = new FileInfo(stream.Name);
        Console.WriteLine("Speed: {0:0.00} MB/s", info.Length / ts.TotalSeconds / 1024.0 / 1024.0);

做同样的事情,但使用 160k 浮点数的一维数组,相同数量的数据以 ~179 MB/s 的速度序列化到磁盘。速度提高 20 倍以上! 为什么使用序列化二维数组的BinaryFormatter性能如此糟糕? 内存中两个数组的底层存储应该是相同的。(我已经完成了不安全的本机 pin_ptr 并在 C++/CLI 中复制到二维数组和从二维数组复制)。

一个骇人听闻的解决方案是实现ISerializable并执行 memcopy(不安全/ptr pinning/block memcopy)将 2D 数组转换为 1D 数组并将其和维度序列化。我正在考虑的另一个选择是切换到protobuf-net.

4

1 回答 1

1

无需放弃您的数据结构或复制值,您可以使用以下代码来实现相同的性能:

            fixed (float* ptr = data)
            {
                byte* arr = (byte*)ptr;
                int size = sizeof(float);

                for (int j = 0; j < data.Length * size; j++)
                {
                    stream.WriteByte(arr[j]);
                }
            }

基本上,您正在自己编写输出流,就像您说的那样,您只是将 float[] 用作 byte[],因为内存结构是相同的。

反序列化是相同的,您可以使用 StreamReader 读取浮点数或 unsafe 并将数据加载到内存中。

如果你有这样的基本需求,我强烈反对使用 protobuf.net。开发速度放慢了,并且基于一个人,所以风险很大(当我试图帮助解决性能问题时,他甚至懒得看我提出的改变)。但是,如果要序列化复杂的数据结构,二进制序列化不会比 protobuf 慢多少,尽管 .NET 平台上并未正式支持后者(Google 发布了 Java、Python 和 C++ 的代码)。

于 2012-01-25T11:18:56.163 回答