优化 - 编码一个字符串并得到 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 中调用这两个方法来进行系统集成。
我目前在一个性能至关重要的环境中工作,这就是我正在做的事情:
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 中调用这两个方法来进行系统集成。