在 Swift 中检查 2 个固定大小的数组是不是相等的最快方法是啥?
Posted
技术标签:
【中文标题】在 Swift 中检查 2 个固定大小的数组是不是相等的最快方法是啥?【英文标题】:What is the fastest way to check 2 fixed size arrays for equality in Swift?在 Swift 中检查 2 个固定大小的数组是否相等的最快方法是什么? 【发布时间】:2020-02-28 18:07:42 【问题描述】:为什么?
给定以下 Swift 代码:
struct DemoStruct
let buf: [UInt8]
init?(fromArray buf: [UInt8])
guard buf.count == 6 else
return nil
self.buf = buf
var containsJustZeros: Bool
// test code
let data = DemoStruct(fromArray: Array(repeating: 0, count: 6))!
if data.containsJustZeros
print("zeros")
对于test code
部分,我已经实现并测量了以下实现:
self.buf == Array(repeating: 0, count: 6)
for dig in self.buf where dig != 0 return false return true
self.buf.elementsEqual(Array(repeating: 0, count: 6))
第一个代码最快(~13 秒/10 000 000 次测试),最后一个代码最慢(~43 秒/10 000 000 次测试)。还有其他可能的实现吗?我想优化我的代码以提高速度并更好地理解 Swift。
【问题讨论】:
您的问题是关于如何检查两个数组是否相等,或者如何检查一个数组是否只包含零?这是两个不同的问题,后者简单地用buf.allSatisfy( $0 == 0 )
完成。
请修正标题,因为它与实际问题有关。
问题是关于平等以及如何优化我的代码以实现快速执行。我选择“零”示例只是为了让一切尽可能简单。我猜你的答案是2. for dig in self.eui where dig != 0 return false return true
的另一种变体
你是如何测试的?你还记得只使用发布版本吗?你在设备上测试过吗?你是怎么测量的?只是检查一下,但我了解到,当人们声称他们测试了某些东西的性能时,他们不会自动相信,因为他们有时不知道如何。
我写了一个 XCTest,同时我循环了提到的属性/函数 10,000,000 次。测试是在我的本地开发机器(Intel 64bit i5)上执行的。测试框架在最后给你一个关于执行时间的总结。
【参考方案1】:
首先:这个Data
结构是一个真的 坏主意,这肯定会导致混乱。 Foundation
已经有一个名为 Data
的结构,而且它无处不在,因为它是用于在无类型字节的杂项数据中穿梭的“通用货币”类型。
此外,您并没有真正从使用[UInt8]
中得到任何信息。只需使用Foundation.Data
。
至于你的主要问题。
-
第一种技术分配一个数组,并使用
==
来比较它。绝对没有理由分配 6 个零。如果buf
有十亿个元素,你会分配十亿个元素吗?浪费。
第二种技术更好,因为您没有分配不必要的元素,只是为了比较。但是,它手动滚动了标准库中已经存在的功能(allSatisfy(_:)
,我稍后会介绍。)
elementsEqual
是==
的更通用版本,它可以将一个序列与任何其他序列进行比较。您选择将其与 6 个零的数组进行比较,但这很糟糕(原因与 0 相同)。相反,您可以使用repeatElement(0, count: 6)
来生成实际上不需要存储n
副本的元素。它只存储一个,并以符合 Collection 协议的方式包装它。
最好的方法是使用allSatisfy
。它速度很快,不会分配任何不必要的东西,并且最重要的是它准确地描述了您想要表达的内容:
var containsJustZeros: Bool
self.buf.allSatisfy byte in byte == 0
但是,我不会在计算属性中实现这一点。那些具有快速的传统期望,而这是对整个缓冲区进行线性扫描。除非您想将结果缓存在存储的布尔属性中,否则我会将其更改为 func
。
【讨论】:
感谢您的回答,我已经更新了我的问题,很抱歉提问时不够准确。 @EvelKnievel 所以你的缓冲区总是 6 个字节? 其实是的,它是一个固定大小的 6 字节缓冲区,我想优化与另一个相同大小的数组的比较 您对性能的渴望如何?如果答案是“非常”(并且要小心并确保您有数据来备份它,因为它是以花费时间、维护开销和整个系统复杂性为代价的),那么您可以只存储一个 6 @ 的元组987654336@,并使用内置的==
运算符将其与(0,0,0,0,0,0)
文字进行比较。如果字节在您的域中具有特定含义,您甚至可以实现自己的比较函数,该函数首先比较那些最有可能不同的字节(更早更频繁地短路)。
这意味着self.buf == [0, 0, 0, 0, 0, 0]
会比self.buf == Array(repeating: 0, count: 6)
更快,因为我们不必分配数组(因为数组已经编译成二进制文件)?以上是关于在 Swift 中检查 2 个固定大小的数组是不是相等的最快方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript:如何在编译时声明固定大小的数组以进行类型检查