Лучшие данные получают/устанавливают uint8 в индексе/маскировании данных

Я пытаюсь создать функцию маски данных.

Я нашел два способа:

  1. использование индексов данных

    • very slow
  2. создать массив из данных, изменить его, а затем преобразовать обратно

    • ~70 times faster
    • использует в 2 раза больше памяти

Почему подписка на данные такая медленная? Есть ли лучший способ получить/установить uint8 в индексе без дублирования памяти?

вот мой тест:

var data = Data(bytes: [UInt8](repeating: 123, count: 100_000_000))

let a = CFAbsoluteTimeGetCurrent()

// data masking
for i in 0..<data.count {
  data[i] = data[i] &+ 1
}

let b = CFAbsoluteTimeGetCurrent()

// creating array
var bytes = data.withUnsafeBytes {
  [UInt8](UnsafeBufferPointer(start: $0, count: data.count))
}
for i in 0..<bytes.count {
  bytes[i] = bytes[i] &+ 1
}
data = Data(bytes: bytes)

let c = CFAbsoluteTimeGetCurrent()
print(b-a) // 8.8887130022049
print(c-b) // 0.12415999174118

person Dmitry Kozlov    schedule 18.02.2017    source источник


Ответы (1)


Я не могу точно сказать, почему первый метод (через индексирование значения Data) такой медленный. Согласно Instruments, много времени тратится на objc_msgSend при вызове методов базового объекта NSMutableData.

Но вы можете изменить байты, не копируя данные в массив:

data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
    for i in 0..<data.count {
        bytes[i] = bytes[i] &+ 1
    }
}

что даже быстрее, чем ваш метод «копировать в массив».

На MacBook я получил следующие результаты:

  • Подписка данных: 7,15 сек.
  • Копировать в массив и обратно: 0,238 сек.
  • withUnsafeMutableBytes: 0,0659 сек.
person Martin R    schedule 18.02.2017