You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift性能优化:大型数组布尔逻辑与比较运算高效实现方案

问题描述

需要处理大型Double和Boolean数组/向量,执行以下操作:

  • 对Double数组:加减乘、大小比较等运算
  • 对Bool数组:AND、OR、NOT等逻辑操作

发现Accelerate框架的vDSP在简单算术运算上性能优异,但大小比较及逻辑运算速度极慢,推测是因为用了map函数实现。求更高效的实现方式。

代码示例

import Accelerate

let myDoubleArray1: [Double] = Array<Double>(repeating: 1.123, count: 1000000)
let myDoubleArray2: [Double] = Array<Double>(repeating: 2.123, count: 1000000)
let myBoolArray1: [Bool] = Array<Bool>(repeating: false, count: 1000000)
let myBoolArray2: [Bool] = Array<Bool>(repeating: true, count: 1000000)

_ = vDSP.multiply(myDoubleArray1, myDoubleArray2) // 耗时约0.5秒 - 性能出色
_ = zip(myDoubleArray1, myDoubleArray2).map {$0 > $1} // 耗时约7秒 - 太慢
_ = zip(myBoolArray1, myBoolArray2).map {$0 && $1} // 耗时约7秒 - 太慢
_ = zip(myBoolArray1, myBoolArray2).map {$0 == $1} // 耗时约7秒 - 太慢
_ = myBoolArray1.map {!$0} // 耗时约7秒 - 太慢
高效实现方案

一、Double数组的大小比较:用Accelerate批量比较函数

Accelerate提供了专门的向量比较函数,直接利用SIMD指令批量处理,性能和算术运算处于同一级别:

示例代码(大于比较)

// 判断array1每个元素是否大于array2对应元素
func compareGreater(_ array1: [Double], _ array2: [Double]) -> [Bool] {
    precondition(array1.count == array2.count, "数组长度必须一致")
    var result = [Bool](repeating: false, count: array1.count)
    
    // 调用vDSP的批量大于比较函数
    vDSP_vgtD(array1, 1, array2, 1, &result, 1, vDSP_Length(array1.count))
    
    return result
}

// 调用示例
let greaterResult = compareGreater(myDoubleArray1, myDoubleArray2)

其他比较操作对应函数:

  • 小于:vDSP_vltD
  • 等于:vDSP_veqD
  • 大于等于:vDSP_vgeD
  • 小于等于:vDSP_vleD
  • 不等于:vDSP_vneD

二、Bool数组的逻辑运算:转UInt8后用Accelerate位运算

Swift的Bool占1字节,Accelerate对整数向量的逻辑运算支持更完善。先将Bool转成UInt8(false→0,true→1),用vDSP位运算处理后再转回Bool:

1. NOT运算(取反)

func boolNot(_ array: [Bool]) -> [Bool] {
    let uint8Array = array.map { $0 ? 1 : 0 }
    var resultUInt8 = [UInt8](repeating: 0, count: array.count)
    
    vDSP_bitwiseNot(uint8Array, 1, &resultUInt8, 1, vDSP_Length(array.count))
    
    return resultUInt8.map { $0 != 0 }
}

// 调用示例
let notResult = boolNot(myBoolArray1)

2. AND运算

func boolAnd(_ array1: [Bool], _ array2: [Bool]) -> [Bool] {
    precondition(array1.count == array2.count, "数组长度必须一致")
    let uint8Array1 = array1.map { $0 ? 1 : 0 }
    let uint8Array2 = array2.map { $0 ? 1 : 0 }
    var resultUInt8 = [UInt8](repeating: 0, count: array1.count)
    
    vDSP_bitwiseAND(uint8Array1, 1, uint8Array2, 1, &resultUInt8, 1, vDSP_Length(array1.count))
    
    return resultUInt8.map { $0 != 0 }
}

// 调用示例
let andResult = boolAnd(myBoolArray1, myBoolArray2)

3. OR运算

func boolOr(_ array1: [Bool], _ array2: [Bool]) -> [Bool] {
    precondition(array1.count == array2.count, "数组长度必须一致")
    let uint8Array1 = array1.map { $0 ? 1 : 0 }
    let uint8Array2 = array2.map { $0 ? 1 : 0 }
    var resultUInt8 = [UInt8](repeating: 0, count: array1.count)
    
    vDSP_bitwiseOR(uint8Array1, 1, uint8Array2, 1, &resultUInt8, 1, vDSP_Length(array1.count))
    
    return resultUInt8.map { $0 != 0 }
}

// 调用示例
let orResult = boolOr(myBoolArray1, myBoolArray2)

4. 相等判断(==)

func boolEqual(_ array1: [Bool], _ array2: [Bool]) -> [Bool] {
    precondition(array1.count == array2.count, "数组长度必须一致")
    let uint8Array1 = array1.map { $0 ? 1 : 0 }
    let uint8Array2 = array2.map { $0 ? 1 : 0 }
    var resultUInt8 = [UInt8](repeating: 0, count: array1.count)
    
    vDSP_veqU(uint8Array1, 1, uint8Array2, 1, &resultUInt8, 1, vDSP_Length(array1.count))
    
    return resultUInt8.map { $0 != 0 }
}

// 调用示例
let equalResult = boolEqual(myBoolArray1, myBoolArray2)

性能说明

以上方案完全基于Accelerate的SIMD指令,能将原本7秒左右的操作压缩到毫秒级。如果需要极致性能,可以直接操作UnsafeBufferPointer避免数组拷贝,上述代码已能应对大部分场景。


内容的提问来源于stack exchange,提问作者Jay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 03:40:48