ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

逐位运算性能如何提高

2019-10-28 16:15:41  阅读:199  来源: 互联网

标签:bitwise-and performance bitwise-operators c


我有一个简单的任务:确定将一些数字(字节数组长度)编码为字节数组并编码最终值所需的字节数(实现本文:Encoded Length and Value Bytes).

最初,我写了一个完成任务的快速方法:

public static Byte[] Encode(Byte[] rawData, Byte enclosingtag) {
    if (rawData == null) {
        return new Byte[] { enclosingtag, 0 };
    }
    List<Byte> computedRawData = new List<Byte> { enclosingtag };
    // if array size is less than 128, encode length directly. No questions here
    if (rawData.Length < 128) {
        computedRawData.Add((Byte)rawData.Length);
    } else {
        // convert array size to a hex string
        String hexLength = rawData.Length.ToString("x2");
        // if hex string has odd length, align it to even by prepending hex string
        // with '0' character
        if (hexLength.Length % 2 == 1) { hexLength = "0" + hexLength; }
        // take a pair of hex characters and convert each octet to a byte
        Byte[] lengthBytes = Enumerable.Range(0, hexLength.Length)
                .Where(x => x % 2 == 0)
                .Select(x => Convert.ToByte(hexLength.Substring(x, 2), 16))
                .ToArray();
        // insert padding byte, set bit 7 to 1 and add byte count required
        // to encode length bytes
        Byte paddingByte = (Byte)(128 + lengthBytes.Length);
        computedRawData.Add(paddingByte);
        computedRawData.AddRange(lengthBytes);
    }
    computedRawData.AddRange(rawData);
    return computedRawData.ToArray();
}

这是一个旧代码,用可怕的方式编写.

现在,我试图通过使用按位运算符或BitConverter类来优化代码.这是按位版本的示例:

public static Byte[] Encode2(Byte[] rawData, Byte enclosingtag) {
    if (rawData == null) {
        return new Byte[] { enclosingtag, 0 };
    }
    List<Byte> computedRawData = new List<Byte>(rawData);
    if (rawData.Length < 128) {
        computedRawData.Insert(0, (Byte)rawData.Length);
    } else {
        // temp number
        Int32 num = rawData.Length;
        // track byte count, this will be necessary further
        Int32 counter = 1;
        // simply make bitwise AND to extract byte value
        // and shift right while remaining value is still more than 255
        // (there are more than 8 bits)
        while (num >= 256) {
            counter++;
            computedRawData.Insert(0, (Byte)(num & 255));
            num = num >> 8;
        }
        // compose final array
        computedRawData.InsertRange(0, new[] { (Byte)(128 + counter), (Byte)num });
    }
    computedRawData.Insert(0, enclosingtag);
    return computedRawData.ToArray();
}

以及BitConverter类的最终实现:

public static Byte[] Encode3(Byte[] rawData, Byte enclosingtag) {
    if (rawData == null) {
        return new Byte[] { enclosingtag, 0 };
    }
    List<Byte> computedRawData = new List<Byte>(rawData);
    if (rawData.Length < 128) {
        computedRawData.Insert(0, (Byte)rawData.Length);
    } else {
        // convert integer to a byte array
        Byte[] bytes = BitConverter.GetBytes(rawData.Length);
        // start from the end of a byte array to skip unnecessary zero bytes
        for (int i = bytes.Length - 1; i >= 0; i--) {
            // once the byte value is non-zero, take everything starting
            // from the current position up to array start.
            if (bytes[i] > 0) {
                // we need to reverse the array to get the proper byte order
                computedRawData.InsertRange(0, bytes.Take(i + 1).Reverse());
                // compose final array
                computedRawData.Insert(0, (Byte)(128 + i + 1));
                computedRawData.Insert(0, enclosingtag);
                return computedRawData.ToArray();
            }
        }
    }
    return null;
}

所有方法都能按预期工作.我使用了Stopwatch class页面上的示例来衡量性能.性能测试使我感到惊讶.我的测试方法执行了1000次该方法的运行,以编码具有100000个元素的字节数组(实际上,仅数组Sixe),平均时间为:

>编码-大约200毫秒
> Encode2-约270ms
> Encode3-大约320ms

我个人喜欢方法Encode2,因为代码看起来更具可读性,但是其性能却不那么好.

问题:您对提高Encode2方法性能或提高Encode可读性有何建议?

任何帮助将不胜感激.

==========================

更新:感谢所有参与此主题的人.我考虑了所有建议,最终得出了以下解决方案:

public static Byte[] Encode6(Byte[] rawData, Byte enclosingtag) {
    if (rawData == null) {
        return new Byte[] { enclosingtag, 0 };
    }
    Byte[] retValue;
    if (rawData.Length < 128) {
        retValue = new Byte[rawData.Length + 2];
        retValue[0] = enclosingtag;
        retValue[1] = (Byte)rawData.Length;
    } else {
        Byte[] lenBytes = new Byte[3];
        Int32 num = rawData.Length;
        Int32 counter = 0;
        while (num >= 256) {
            lenBytes[counter] = (Byte)(num & 255);
            num >>= 8;
            counter++;
        }
        // 3 is: len byte and enclosing tag
        retValue = new byte[rawData.Length + 3 + counter];
        rawData.CopyTo(retValue, 3 + counter);
        retValue[0] = enclosingtag;
        retValue[1] = (Byte)(129 + counter);
        retValue[2] = (Byte)num;
        Int32 n = 3;
        for (Int32 i = counter - 1; i >= 0; i--) {
            retValue[n] = lenBytes[i];
            n++;
        }
    }
    return retValue;
}

最终,我从列表移到了固定大小的字节数组.现在,针对同一数据集的平均时间约为65毫秒.列表(似乎不是按位操作)给我的性能造成了重大损失.

解决方法:

这里的主要问题几乎可以肯定是List的分配,以及在插入新元素以及将list最终转换为数组时所需的分配.这段代码可能大部分时间都花在了垃圾回收器和内存分配器上.相比较而言,使用位运算符与不使用位运算符的意义可能很小,我将研究减少您首先分配的内存量的方法.

一种方法是发送对预先分配的字节数组的引用,并向该数组中的位置发送索引,而不是分配并返回数据,然后返回一个整数以告知已写入的字节数.在大型阵列上工作通常比在许多小型对象上工作更有效率.正如其他人提到的,使用探查器,查看代码在哪里花费时间.

当然,我提到的优化将使您的代码本质上更底层,并且更接近于您通常在C语言中所做的代码,但是通常在可读性和性能之间进行权衡.

标签:bitwise-and,performance,bitwise-operators,c
来源: https://codeday.me/bug/20191028/1953750.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有