我得到了一种计算UIImage中白色像素的方法,我需要遍历所有像素以增加找到的每个白色像素的计数。我正在尝试改善它的性能,但是找不到更好的方法。有什么想法吗?
func whitePixelCount() -> Int {
let width = Int(image.size.width)
let height = Int(image.size.height)
var counter = 0
for x in 0..<(width*scale) {
for y in 0..<(height*scale) {
// We multiply per 4 because of the 4 channels, RGBA, but later we just use the Alpha
let pixelIndex = (width * y + x) * 4
if pointer[pixelIndex + Component.alpha.rawValue] == 255 {
counter += 1
}
}
}
return counter
}
指针来自:
guard let cfdata = self.image.cgImage?.dataProvider?.data,
let pointer = CFDataGetBytePtr(cfdata) else {
return nil
}
通常,可以通过用while循环替换for循环来提高big(o)的性能,这就是说while x 另一种方法是将映像拆分为单独的组件,然后将它们发送到不同的线程,然后重新组合结果数组。您将要使用gcd * workitems async来执行此操作。
一种非常简单的方法是使用concurrentPerform
并行化例程:
例如,这是一个非并行例程:
var total = 0
for x in 0..<maxX {
for y in 0..<maxY {
if ... {
total += 1
}
}
}
print(total)
您可以通过将for
的x
循环替换为concurrentPerform
来并行化它:
var total = 0
let syncQueue = DispatchQueue(label: "...")
DispatchQueue.concurrentPerform(iterations: maxX) { x in
var subTotal = 0
for y in 0..<maxY {
if ... {
subTotal += 1
}
}
syncQueue.sync {
total += subTotal
}
}
print(total)
所以,想法是:
for
替换外部concurrentPerform
循环;total
的每个迭代尝试更新y
,对于每个线程都具有一个subTotal
变量,并且仅在最后更新count
(以最小化total
的竞争);和total
以确保线程安全。我试图使示例尽可能简单,但是甚至可以进行其他优化:
如果每个线程上的工作量不足(例如maxX
不太大),则并行化例程的开销会开始抵消让多个内核参与计算的好处。因此,您可以在每次迭代中“跨越” y
的多行。
不同的同步技术提供不同的性能。例如。您可以通过在协议扩展中定义NSLock
方法来使用sync
(传统观点认为该速度较慢,但我最近的基准测试表明,在许多情况下,性能可能比GCD更好)(以提供一种不错的,安全的方法这样使用锁):
// Adapted from Apple’s `withCriticalSection` code sample
extension NSLocking {
func sync<T>(_ closure: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try closure()
}
}
然后您可以执行以下操作:
let lock = NSLock()
DispatchQueue.concurrentPerform(iterations: maxX) { x in
var subTotal = 0
for y in 0..<maxY {
if ... {
subTotal += 1
}
}
lock.sync {
total += subTotal
}
}
print(total)
随意尝试所需的任何同步机制。但是,这样做的想法是,如果要从多个线程访问total
,请确保以线程安全的方式进行访问。如果您要检查线程安全性,请暂时打开“ Thread Sanitizer”。