Советы по быстрой производительности

iPhone X:

  • Чип A11 Bionic с 64-битной архитектурой
  • Нейронный двигатель
  • Встроенный сопроцессор движения M11
  • 3 ГБ оперативной памяти

и эта статья посвящена мельчайшим деталям производительности. Звучит скучно или банально ???

Ключевым аспектом написания высокооптимизированного программного обеспечения является понимание лежащих в основе накладных расходов на производительность.

Распределения

Каждый раз, когда вы инициализируете объект, задайте себе вопрос. Будет ли этот экземпляр размещен в стеке или куче. Стек - это простая структура данных с двумя основными операциями. Push и Pop. Вы можете нажать на конец стека и выдвинуть конец стека, удерживая указатель на конец стека, где куча позволяет вам выделять память с динамической жизнью. время. Он должен искать неиспользуемый блок памяти для выделения, а затем повторно вставлять блок памяти для освобождения. Heap также должен управлять накладными расходами на безопасность потоков, поскольку несколько потоков будут выделять память. Таким образом, очевидно, что размещение в стеке выполняется намного быстрее, чем в куче.

Структуры и классы (когда и что использовать)

Объекты структуры хранятся в стеке, а объекты класса хранятся в куче. Допустим, мы хотим реализовать модель человека.

struct Person {
  var age: Int = 20
}
let obj1 = Person()
let obj2 = obj1
class Person {
  var age: Int = 20
}
let obj1 = Person()
let obj2 = obj1

Какой из них быстрее ??

Объект структуры размещается в стеке, а объект класса размещается в куче. Куча также имеет накладные расходы на подсчет ссылок для экземпляров класса. Итак, в этом случае размещение в стеке было намного быстрее, чем в куче. Теперь давайте взглянем на более продвинутую модель Person.

struct Person {
var firstName: String
var middleName: String
var lastName: String
}
let obj1 = Person()
let obj2 = obj1
class Person {
var firstName: String
var middleName: String
var lastName: String
}
let obj1 = Person()
let obj2 = obj1

Какой сейчас быстрее ?? Давайте взглянем.

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

Я знаю, что вы умный разработчик и не хотите этим заниматься.

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

Отправка метода (статическая или динамическая)

Следующее, что вам нужно сделать, это то, будет ли мой метод отправляться статически или динамически. Динамическая диспетчеризация требует больших затрат, поскольку требует реализации vTable или witnessTable, но в то же время мы также хотим добиться динамизма в нашем коде.

Используйте протокол-ориентированное программирование вместо наследования

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

Использовать универсальные шаблоны

Generics дает вам возможность полиморфизма без динамической диспетчеризации. Пример:

func power(_p: ProtocolType) {
 // this method will be dynamically dispatched
}
power(SomeTypeWhichConformsToProtocolType)
func power<T: ProtocolType>(_p: T)
 // this method will be statically dispatched
}
power(SomeTypeWhichConformsToProtocolType)

Универсальная специализация создает версию метода для конкретного типа. Если универсальная реализация представляет собой структуру, вы также можете получить выделение в стеке без подсчета ссылок, если не задействована семантика ссылок. Вы можете получить силу полиморфизма, даже размещая объекты в стеке.

Используйте выпускные классы

Используйте Final, если вы уверены, что класс не наследуется где-либо в проекте. Все методы становятся статически отправленными, когда класс является Final.

Использовать частный и файловый доступ

Применение ключевых слов private или fileprivate ограничивает видимость объявления в файле. Таким образом, отсутствие таких объявлений позволяет компилятору автоматически вывести ключевое слово final и удалить косвенные вызовы.

Используйте перечисления вместо строк

Перечисления размещаются в стеке, а строки - в куче. Перечисления не имеют ссылочного типа, такого как строки. Перечисления также безопасны по типу.

Эта история публикуется в журнале Noteworthy, куда ежедневно приходят более 10 000 читателей, чтобы узнать о людях и идеях, формирующих наши любимые продукты.

Следите за нашей публикацией, чтобы увидеть больше историй о продуктах и ​​дизайне, представленных командой Journal.