Повышаем производительность циклов в Swift на 87%

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

“loop unrolling” в Swift или как разогнать ваш код с помощью одного небольшого фокуса.

Фото Fernando Rodrigues на Unsplash
Фото Fernando Rodrigues на Unsplash

Современные устройства настолько мощные, что из-за этого некоторые из нас стали упускать из виду важность производительности и оптимизации. И действительно, зачем вообще беспокоиться об оптимальном использовании ресурсов, когда в наших Mac или iPad зашит такой высокопроизводительный монстр, как M2 SoC? Однако принятие такого рода мышления является пагубным. Очень важно время от времени пересматривать основы и принимать на вооружение дельные советы по оптимизации кода. Они могут обогатить наши знания и улучшить наши навыки разработки программных продуктов, даже если они не всегда могут пригодиться на практике.

Сегодня мы с вами рассмотрим функцию, которой каждый из нас пользуется чуть ли не ежедневно: метод filter.

Пишем собственный метод filter

Фильтрация массива — типовая задача, поэтому было бы интересно попробовать ее оптимизировать.

Давайте возьмем массив имен и попробуем отфильтровать конкретное имя:

    func filterName(name: String,
                                   fromArray collection: [String]) -> [String] {
        var result: [String] = []
        
        let indices = collection.indices
        var currentIndex = indices.lowerBound
        
        while currentIndex < indices.upperBound {
            let tempName = collection[currentIndex]
            if tempName == name {
                result.append(tempName)
            }
            currentIndex = indices.index(after: currentIndex)
        }
        
        return result
    }

Код для выполнения этой задачи довольно прост. Мы перебираем массив от нижней границы к верхней, обращаемся к каждому его элементу и производим сравнение. Наконец, мы возвращаем все отфильтрованные элементы.

Я провел тест на 500 000 элементов, и время выполнения составило 0.056 секунды. Неплохо! Теперь давайте рассмотрим некоторые потенциальные оптимизации для дальнейшего повышения производительности.

Использование forEach

Кое-кто из вас уже мог заметить, что предыдущая функция выглядит немного громоздкой. В конце концов, зачем возиться с созданием нижних и верхних границ, когда мы можем просто использовать для массива метод forEach? Давайте посмотрим на пример того же кода, но реализованный через цикл forEach:

    func filterName(name: String, fromArray collection: [String]) -> [String] {
        var result: [String] = []
        for tempName in collection {
            if tempName == name {
                result.append(tempName)
            }
        }
        return result
    }

Теперь, когда я запущу этот код на тех же самых 500 000 элементах, результат будет получен куда быстрее. Время выполнения составило лишь 0.031 секунды. Это значительное улучшение — на целых 42%!

Но за счет чего это происходит? Что ж, под капотом сама функция forEach все еще выполняет итерации. Однако стоит отметить, что forEach — это встроенный метод, который может быть оптимизирован средой выполнения или компилятором, что может быть причиной ощутимого повышения производительности по сравнению с циклами, реализованными вручную.

Итерирование в Swift часто более оптимизировано, чем доступ к элементам по отдельности. Последовательная итерация позволяет компилятору реализовать эффективный доступ к элементам и даже выполнять предварительную выборку элементов, чтобы свести все возможные задержки к минимуму. Однако можем ли мы расширить границы возможной оптимизации еще дальше? Давайте попробуем найти еще пару способов улучшить наш код

Источник: https://habr.com/ru/companies/otus/articles/752222/


Интересные статьи

Интересные статьи

«Умирающая Земля» — это поджанр научного фэнтези или фантастики, в котором действие происходит в далеком будущем в мире, который кажется обреченным на скорую гибель. В нем нет быстрых и трагических из...
В последние несколько недель мы рассмотрели многие аспекты создания пользовательских слоев с использованием нового Layout протокола в Swift UI, однако нам еще многое предстоит обсудить. На э...
Третья версия SwiftUI принесла нам несколько модификаторов представления (view modifiers), которые позволяют нам одинаково обрабатывать семантически похожие операции для разных представлений. Например...
Gears Tactics — динамичная пошаговая стратегия во вселенной одной из самых известных игровых франшиз — Gears of War. Кроме того, это первая игра, поддерживающая одну из основных функц...
На самом деле, речь сегодня пойдёт не только о бывших в использование какое-либо время накопителях, ведь проблема низкого быстродействия может затронуть даже только что принесённый из магазина SS...