Самый быстрый способ создать Swift Array <Float>с фиксированным количеством - PullRequest
0 голосов
/ 23 января 2019

Я заметил, что это:

let a = [Float](repeating: 0, count: len)

занимает значительно больше времени, чем просто

let p = UnsafeMutablePointer<Float>.allocate(capacity: len)

Однако небезопасный указатель не так удобен в использовании, и может потребоваться создать Array<Float> для передачи на другой код.

let a = Array(UnsafeBufferPointer(start: p, count: len))

Но это абсолютно убивает, и быстрее создать Array с заполненными нулями.

Есть идеи, как создать Array быстрее и в то же время иметь под рукой фактический Array<Float>? В контексте моего проекта я, вероятно, могу справиться с небезопасным указателем внутри и обернуть его Array только при необходимости вне модуля.

Быстрый тест на все ответы в этом посте:

let len = 10_000_000

benchmark(title: "array.create", num_trials: 10) {
    let a = [Float](repeating: 0, count: len)
}

benchmark(title: "array.create faster", num_trials: 10) {
    let p = UnsafeMutableBufferPointer<Float>.allocate(capacity: len)
}

benchmark(title: "Array.reserveCapacity ?", num_trials: 10) {
    var a = [Float]()
    a.reserveCapacity(len)
}

benchmark(title: "ContiguousArray ?", num_trials: 10) {
    let a = ContiguousArray<Float>(repeating: 0, count: len)
}

benchmark(title: "ContiguousArray.reserveCapacity", num_trials: 10) {
    var a = ContiguousArray<Float>()
    a.reserveCapacity(len)
}
benchmark(title: "UnsafeMutableBufferPointer BaseMath", num_trials: 10) {
    let p = UnsafeMutableBufferPointer<Float>(len) // Jeremy's BaseMath
    print(p.count)
}

Результаты: (на 10 млн. Поплавков)

array.create: 9.256 ms

array.create: 0,004 мс

Array.reserveCapacity?: 0,264 мс

ContiguousArray?: 10,154 мс

ContiguousArray.reserveCapacity: 3,251 мс

UnsafeMutableBufferPointer BaseMath: 0,049 мс

Я делаю это adhocly запуска приложения на симуляторе iphone в режиме Release. Я знаю, что, вероятно, мне следует делать это в командной строке / автономно, но так как я планирую написать это как часть приложения, это может быть хорошо.

Для того, что я пытался сделать, UnsafeMutableBufferPointer выглядел великолепно, но вы должны использовать BaseMath и все его соответствия. Если вам нужен более общий или иной контекст. Обязательно прочитайте все и решите, какой из них вам подходит.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Если вам нужна производительность и вы знаете нужный размер, вы можете использовать reserveCapacity (_:) , это будет предварительно выделять память, необходимую для содержимого массива. По документации Apple:

Если вы добавляете в массив известное количество элементов, используйте этот метод, чтобы избежать множественных перераспределений. Этот метод гарантирует, что массив имеет уникальное, изменяемое, непрерывное хранилище с пространством, выделенным как минимум для запрошенного количества элементов.

Вызов метода reserveCapacity (_ :) для массива с мостовым хранилищем инициирует копирование в смежное хранилище, даже если в существующем хранилище есть место для хранения элементов minimalCapacity.

По соображениям производительности размер вновь выделенного хранилища может быть больше, чем запрошенная емкость. Используйте свойство емкости массива, чтобы определить размер нового хранилища.

0 голосов
/ 23 января 2019

Это самая близкая вещь к тому, что я хочу.Есть библиотека с именем BaseMath (созданная Джереми Ховардом), и есть новый вызов классов AlignedStorage и UnsafeMutableBufferPointer.Он наделен большой математикой и очень быстрым, так что это уменьшает количество управления указателями при манипулировании математическим алгоритмом.

Но это еще предстоит проверить, этот проект очень новый.Я оставлю этот вопрос открытым, чтобы узнать, может ли кто-то предложить что-то лучшее.

Примечание: это самый быстрый способ в контексте того, что я делаю.Если вам действительно нужен хороший тип значения структуры Array (и варианты), см. Другие ответы.

...