优化 - 编码一个字符串并得到 3 个字节的十六进制表示

Optimization - Encode a string and get hexadecimal representation of 3 bytes

我目前在一个性能至关重要的环境中工作,这就是我正在做的事情:

var iso_8859_5 = System.Text.Encoding.GetEncoding("iso-8859-5");

var dataToSend = iso_8859_5.GetBytes(message);

我需要将字节按 3 分组,所以我有一个 for 循环来执行此操作(我是循环的迭代器):

byte[] dataByteArray = { dataToSend[i], dataToSend[i + 1], dataToSend[i + 2], 0 };

然后我从这 4 个字节中得到一个整数

BitConverter.ToUInt32(dataByteArray, 0)

最后,整数被转换为十六进制字符串,我可以将其放入网络数据包中。

最后两行重复了大约150次

我目前的执行时间达到 50 毫秒,理想情况下我希望达到 0...有没有我不知道的更快的方法?

更新

刚试过

string hex = BitConverter.ToString(dataByteArray);
hex.Replace("-", "")

直接获取十六进制字符串但是慢了3倍

Ricardo Silva 的回答改编

public byte[][] GetArrays(byte[] fullMessage, int size)
        {
            var returnArrays = new byte[(fullMessage.Length / size)+1][];
            int i, j;
            for (i = 0, j = 0; i < (fullMessage.Length - 2); i += size, j++)
            {
                returnArrays[j] = new byte[size + 1];

                Buffer.BlockCopy(
                    src: fullMessage,
                    srcOffset: i,
                    dst: returnArrays[j],
                    dstOffset: 0,
                    count: size);

                returnArrays[j][returnArrays[j].Length - 1] = 0x00;
            }
            switch ((fullMessage.Length % i))
        {
            case 0: {
                returnArrays[j] = new byte[] { 0, 0, EOT, 0 };
            } break;
            case 1: {
                returnArrays[j] = new byte[] { fullMessage[i], 0, EOT, 0 };
            } break;
            case 2: {
                returnArrays[j] = new byte[] { fullMessage[i], fullMessage[i + 1], EOT, 0 };
            } break;
        }    
            return returnArrays;
        }

在下一行之后,您将获得总字节数组。 var dataToSend = iso_8859_5.GetBytes(消息);

我的建议是使用 Buffer.BlockCopy 并测试它是否会比您当前的方法更快。

试试下面的代码,告诉我们是否比您当前的代码更快:

    public byte[][] GetArrays(byte[] fullMessage, int size)
    {
        var returnArrays = new byte[fullMessage.Length/size][];

        for(int i = 0, j = 0; i < fullMessage.Length; i += size, j++)
        {
            returnArrays[j] = new byte[size + 1];

            Buffer.BlockCopy(
                src: fullMessage,
                srcOffset: i,
                dst: returnArrays[j],
                dstOffset: 0,
                count: size);

            returnArrays[j][returnArrays[j].Length - 1] = 0x00;
        }

        return returnArrays;
    }

EDIT1:我运行 下面的测试,输出是 245900ns(或 0,2459ms)。

[TestClass()]
public class Form1Tests
{
    [TestMethod()]
    public void GetArraysTest()
    {
        var expected = new byte[] { 0x30, 0x31, 0x32, 0x00 };
        var size = 3;

        var stopWatch = new Stopwatch();
        stopWatch.Start();

        var iso_8859_5 = System.Text.Encoding.GetEncoding("iso-8859-5");

        var target = iso_8859_5.GetBytes("012");
        var arrays = Form1.GetArrays(target, size);

        BitConverter.ToUInt32(arrays[0], 0);

        stopWatch.Stop();

        foreach(var array in arrays)
        {
            for(int i = 0; i < expected.Count(); i++)
            {
                Assert.AreEqual(expected[i], array[i]);
            }
        }

        Console.WriteLine(string.Format("{0}ns", stopWatch.Elapsed.TotalMilliseconds * 1000000));
    }
}

编辑 2

我看了你的代码,我只有一个建议。我知道您需要添加 EOF 消息,并且输入数组的长度不会始终是您想要中断的大小的倍数。 但是,现在下面的代码有两个职责,打破了 SOLID 概念。 S 谈论 单一职责 - 每个方法都有一个,而且只有一个职责。 您发布的代码有两个职责(将输入数组分成 N 个较小的数组并添加 EOF)。尝试想办法创建两个完全独立的方法(一个将数组分解为 N 个其他数组,另一个将 EOF 放入您传递的任何数组中)。这将允许您为每个方法创建单元测试(并保证它们有效并且永远不会因任何更改而中断),并从您的 class 中调用这两个方法来进行系统集成。