关于C#中字节数组复制的五种方法

说实话,我的C#水平也不是很高,这几种C#字节数组的复制方法均是在网上搜来的,在进行测试后发现了一个有趣的问题,希望能和大家讨论一下。


首先是借鉴了文章《比较C#中几种常见的复制字节数组方法的效率 》,网址是:http://blog.csdn.net/jiangzhanchang/article/details/9998229,这篇文章中使用了4种方法,我这里对它进行了一个补充,增加了下面一片文章中的指针复制方法。

另一篇是微软官网《C#编程指南》中的《如何:使用指针复制字节数组(C# 编程指南)》,网址是:https://msdn.microsoft.com/zh-cn/library/28k1s2k6.aspx


下面是测试代码,主体结构是按照《比较C#中几种常见的复制字节数组方法的效率 》文章中的代码写的,后面只是增加了一部分指针复制的部分。

    class Program
    {
        private const int TestTimes = 10000000;

        static void Main(string[] args)
        {
            var testArrayCopy = new TestArrayCopy();
            TestCopy(testArrayCopy.TestBinaryReader, "Binary.ReadBytes");
            TestCopy(testArrayCopy.TestConvertToList, "ConvertToList");
            TestCopy(testArrayCopy.TestArrayDotCopy, "Array.Copy");
            TestCopy(testArrayCopy.TestBlockCopy, "Buffer.BlockCopy");
            TestCopy(testArrayCopy.TestPtrCopy, "PtrCopy");
            Console.Read();
        }

        private static void TestCopy(Action testMethod, string methodName)
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
            for (int i = 0; i < TestTimes; i++)
            {
                testMethod();
            }
            testMethod();
            stopWatch.Stop();
            Console.WriteLine("{0}: {1} seconds, {2}.", methodName, stopWatch.Elapsed.Seconds, stopWatch.Elapsed.Milliseconds);
        } 
    } 


    class TestArrayCopy
    {
        private readonly byte[] _sourceBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        public void TestBinaryReader()
        {
            var binaryReader = new BinaryReader(new MemoryStream(_sourceBytes));
            binaryReader.ReadBytes(_sourceBytes.Length);
        }

        public void TestConvertToList()
        {
            IList<byte> bytesSourceList = new List<byte>(_sourceBytes);
            var bytesNew = new byte[_sourceBytes.Length];
            bytesSourceList.CopyTo(bytesNew, 0);
        }

        public void TestArrayDotCopy()
        {
            var bytesNew = new byte[_sourceBytes.Length];
            Array.Copy(_sourceBytes, 0, bytesNew, 0, _sourceBytes.Length);
        }

        public void TestBlockCopy()
        {
            var bytesNew = new byte[_sourceBytes.Length];
            Buffer.BlockCopy(_sourceBytes, 0, bytesNew, 0, _sourceBytes.Length);
        }

        public void TestPtrCopy()
        {
            var bytesNew = new byte[_sourceBytes.Length];
            PtrCopy.Copy(_sourceBytes, 0, bytesNew, 0, _sourceBytes.Length);
        }
    }

接下来是指针复制的代码:

    class PtrCopy
    {
        public static unsafe void Copy(byte[] source, int sourceOffset, byte[] target, int targetOffset, int count)
        {
            // If either array is not instantiated, you cannot complete the copy.
            if ((source == null) || (target == null))
            {
                throw new System.ArgumentException();
            }

            // If either offset, or the number of bytes to copy, is negative, you
            // cannot complete the copy.
            if ((sourceOffset < 0) || (targetOffset < 0) || (count < 0))
            {
                throw new System.ArgumentException();
            }

            // If the number of bytes from the offset to the end of the array is 
            // less than the number of bytes you want to copy, you cannot complete
            // the copy. 
            if ((source.Length - sourceOffset < count) ||
                (target.Length - targetOffset < count))
            {
                throw new System.ArgumentException();
            }

            // The following fixed statement pins the location of the source and
            // target objects in memory so that they will not be moved by garbage
            // collection.
            fixed (byte* pSource = source, pTarget = target)
            {
                // Set the starting points in source and target for the copying.
                byte* ps = pSource + sourceOffset;
                byte* pt = pTarget + targetOffset;

                // Copy the specified number of bytes from source to target.
                for (int i = 0; i < count; i++)
                {
                    *pt = *ps;
                    pt++;
                    ps++;
                }
            }
        }
    }

下面是运行结果:

Debug环境下:

Binary.ReadBytes: 1 seconds, 136.
ConvertToList: 1 seconds, 341.
Array.Copy: 0 seconds, 375.
Buffer.BlockCopy: 0 seconds, 291.
PtrCopy: 0 seconds, 475.

Release环境下:

Binary.ReadBytes: 1 seconds, 108.
ConvertToList: 1 seconds, 262.
Array.Copy: 0 seconds, 330.
Buffer.BlockCopy: 0 seconds, 251.
PtrCopy: 0 seconds, 138.

从结果可以看出,同样的指针复制算法,在Debug环境下的速度不是最快的,只排在第三位,但是在Release环境下却是最快的,甚至比排在第二位的Buffer.BlockCopy方法快了将近一倍!

这个是什么原因造成的?使用非安全代码会有什么样的问题?希望我这次的测试能够抛砖引玉,大家能够相互讨论一下。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值