【问题标题】:How can I simplify and optimize this checksumming code?如何简化和优化此校验和代码?
【发布时间】:2011-01-27 03:53:43
【问题描述】:

好的,这段代码可以工作,但我认为它在中间有一些必要的步骤来获得结果。关于如何使它更紧的任何想法?

Public Function CalCheckSum(ByVal ByteList As List(Of Byte)) As List(Of Byte)
    Dim total As Integer = 0
    For Each b As Byte In ByteList
        total = total + b

    Next
    Dim modedVal As Integer = 0
    modedVal = total Mod &H100
    Dim negatedValue As Integer = 0
    negatedValue = &H100 - modedVal
    Dim charList As List(Of Char) = Hex(negatedValue).ToCharArray.ToList
    Dim returnList As New List(Of Byte)
    For Each ch As Char In charList
        returnList.Add(Asc(ch))

    Next
    Return returnList

End Function

顺便说一句,这是我用来测试的:

Dim blist As New List(Of Byte)
blist.Add(&H52)
blist.Add(&H34)
blist.Add(&H35)
blist.Add(&H31)
blist.Add(&H32)
blist.Add(&H33)
blist.Add(&H34)
blist.Add(&H30)

blist.Add(&H30)
blist.Add(&H30)
blist.Add(&H30)
blist.Add(&H46)
blist.Add(&H46)
blist.Add(&H46)
blist.Add(&H46)
blist.Add(&H42)
blist.Add(&H4B)
blist.Add(&H9)
blist.Add(&H44)

Dim b As List(Of Byte) = CalCheckSum(blist)

b 的正确值为:

  • b(0) = &H43
  • b(1) = &H39

【问题讨论】:

  • 我对校验和算法了解不多,但&H100 看起来很奇怪。你确定不想要&HFF
  • 您是否有特殊原因要重新发明自己的校验和算法,而不是使用 .NET Framework 在System.Security.Cryptography namespace 中已经提供的算法之一?例如,MD5 哈希通常是一个完美可行的解决方案。
  • Cody Gray:我没有发明自己的校验和算法。以上是与已经使用该算法的嵌入式硬件设备进行通信。我只是在 vb.net 中编写它,这样我就可以与该设备进行通信。正如我所说,上面的代码可以与设备通信......只是代码看起来很乱。
  • 嗨 Chris - 是的 &H100(或 256 十进制)显然是正确的。从原始校验和文档中:总结所有字段并计算 mod 0x100。然后将其取反以得到两个字节的校验和。校验和值转换为两个十六进制数字并插入到消息中

标签: vb.net algorithm performance optimization checksum


【解决方案1】:

老实说,我不确定您为什么要浪费时间来优化它。在循环中调用该函数超过 100,000 次需要不到 20 毫秒。即使这是您的应用程序中的“热点”之一(因为您说它与嵌入式硬件设备通信),您也不太可能通过优化您拥有的代码看到任何明显的速度提升。

但只是为了好玩,我决定看看我是否无法优化一些东西......这是我想出的:

  1. 删除多余的List(Of Char) 创建。您已经使用 ToCharArray 方法将值转换为数组。为什么要为此付出代价调用ToList,只是为了遍历它?您也可以通过数组进行迭代。这将时间缩短到 8 秒左右,以最小的努力实现了相当大的加速。

  2. 您还可以将新List(Of Byte) 的近似大小作为参数传递给构造函数。您已经从 charArray 的大小中知道了这一点,因为您只是将这些元素中的每一个重新添加回去。当您只使用两个项目时,这没有任何区别,如您提供的示例中所示,但它可以使大量元素的效率稍微提高一些,因为List 不必在循环期间的任何时候动态调整大小。

  3. AscAscWConvert.ToInt32 之间绝对没有区别。我明确地测量了它们中的每一个,只是为了看看。我的直觉是将其更改为AscW,但显然这并不重要。许多人会对使用 VB 特定的习惯用法嗤之以鼻,并推荐他们认为 .NET Framework 提供的更通用的方法。事实证明,由于所有 VB 特定的代码都是在与替代代码相同的托管代码中编写的,因此您使用哪个是一个简单的偏好问题。

  4. 否则将List(Of T) 替换为简单的数组也不会产生任何明显的差异。由于List 更容易在函数外部使用,您不妨将其保留为返回的类型。

所以我的最终代码看起来像这样:

Public Function CalCheckSum(ByVal ByteList As List(Of Byte)) As List(Of Byte)
    Dim total As Integer = 0
    For Each b As Byte In ByteList
        total = total + b
    Next

    Dim negatedValue As Integer = 0
    negatedValue = &H100 - (total Mod &H100)

    Dim charArray As Char() = Hex(negatedValue).ToCharArray()

    Dim returnList As New List(Of Byte)(charArray.Length)
    For Each ch As Char In charArray
        returnList.Add(CByte(Asc(ch)))
    Next

    Return returnList
End Function

即使循环运行这 999,000 次,我始终将其计时在 62 到 64 毫秒之间。

您也可以使用 LINQ。这不是我真正的领域,我怀疑你会看到任何可测量的速度提高(它仍然必须在幕后进行相同数量的循环和迭代)。它提供的最大好处是您的代码更简单,看起来更干净。我很惊讶有人尚未发布此解决方案。

编辑:顺便说一句,您的原始代码没有为我编译。我必须添加 CByte 运算符才能将从 Asc 运算符返回的 Integer 值转换为 Byte 类型。这告诉我你没有在 Option Strict 上编程。 但您应该这样做。您必须在项目的属性中明确设置选项,但强类型的好处远远超过检查和修复某些现有代码的成本。您甚至可能会注意到性能提升,尤其是在您无意中使用了大量后期绑定的情况下。

【讨论】:

  • 科迪·格雷:非常感谢。这正是我正在寻找的那种回应。我绝不是全职(或兼职)程序员,所以我非常感谢这种详细程度的解释,因为它确实有助于学习。我非常感谢您花时间测试并写出来。另外,感谢关​​于 option strict 的注释——我将开始使用它进行编程,看看我是怎么做的。再次感谢您!
  • @avword:不客气。当然,我也不是全职程序员。 ;-) 但我确实喜欢一些健康的优化,即使它是邪恶的。我很高兴能够让您更深入地了解幕后发生的事情。一些技巧(例如消除您创建的额外List)便宜、简单且直接。这些是您最好实施的优化。除此之外的任何事情都是太多的工作和太大的风险,以获得最小的回报。经验法则是过早的优化是邪恶的。这意味着你不应该优化,直到你知道一块
  • (续)代码太慢了。定时是最好的办法。为了让您以后可以自己测试执行速度,请查看 .NET Framework 提供的Stopwatch class。有一个很好的例子说明它是如何在那个页面上使用的,而且一点也不难。这就是我在这里所做的一切,所以你甚至不再需要我了。 :-) 祝你好运!
猜你喜欢
  • 1970-01-01
  • 2022-11-23
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多