0Pricing
Swift Academy · Урок

Оптимизация узких мест: COW, встраивание и специализация

Применяйте @inline, @_specialize и оптимизацию типов-значений на основе данных профилировщика.

«Оптимизация узких мест: COW, встраивание и специализация» — бесплатный урок Swift Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Сначала выявите проблему, затем оптимизируйте

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

// Measure → Identify → Optimise → Re-measure
// A 10ms function called once is less important than
// a 0.1ms function called 10,000 times per frame

Копирование при записи (COW)

Типы-значения Swift (Array, Dictionary) используют COW: хранилище разделяется до тех пор, пока не произойдёт изменение, что позволяет избежать ненужного копирования.

var a = [1, 2, 3, 4, 5]
var b = a         // no copy yet, shared buffer
b.append(6)       // copy happens here (b mutates)
print(a.count)    // 5 — a unchanged

Обеспечение COW в пользовательских типах

Реализуйте COW в пользовательских типах-значениях: поместите изменяемое состояние в ссылочный тип и копируйте его перед изменением.

struct Matrix {
  private class Storage { var data: [[Double]] }
  private var storage = Storage()
  private mutating func ensureUnique() {
    if !isKnownUniquelyReferenced(&storage) {
      storage = Storage(data: storage.data)  // copy on write
    }
  }
  mutating func set(row: Int, col: Int, value: Double) {
    ensureUnique()
    storage.data[row][col] = value
  }
}

@inline(__always)

Заставьте компилятор встраивать функцию в каждое место вызова, устраняя накладные расходы вызова для небольших функций в тесных циклах.

@inline(__always)
func clamp(_ value: Float, _ min: Float, _ max: Float) -> Float {
  return Swift.max(min, Swift.min(max, value))
}

@inline(never)

Запретите встраивание, чтобы уменьшить размер кода или заставить компилятор считать участок редко выполняемым.

@inline(never)
func handleUnexpectedError(_ error: Error) {
  // Large error-handling block — never inline to keep hot path small
}

@_specialize для обобщённых типов

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

@_specialize(where T == Float)
@_specialize(where T == Double)
func normalize<T: FloatingPoint>(_ values: [T]) -> [T] {
  let max = values.max()!
  return values.map { $0 / max }
}

Оптимизация всего модуля

WMO (включённая в сборках для выпуска) позволяет компилятору выполнять встраивание и специализацию за границами файлов внутри модуля.

// Xcode: Build Settings → Swift Compiler → Code Generation
// Optimization Level: Optimize for Speed (-O)
// Compilation Mode: Whole Module
// Enables cross-file inlining and dead code elimination

Снижение накладных расходов ARC

Частое создание ссылочных типов на узких участках вызывает накладные расходы ARC на удержание и освобождение ссылок. Предпочитайте типы-значения или кэшируйте ссылки.

// HOT PATH:
for _ in 0..<1_000_000 {
  let obj = HeavyClass()  // alloc + dealloc + ARC overhead
}
// BETTER: allocate once outside the loop
let obj = HeavyClass()
for _ in 0..<1_000_000 { obj.process() }

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

ContiguousArray гарантирует непрерывное хранение (в отличие от Array для элементов-классов), повышая эффективность кэша в тесных циклах.

var nums = ContiguousArray<Float>(repeating: 0, count: 10_000)
// Faster iteration than Array<Float> for bridged-to-ObjC types

Сокращение обращений к таблицам свидетелей протоколов

Динамическая диспетчеризация протоколов использует таблицы свидетелей. Обобщённые типы и специализация заменяют обращения к таблицам свидетелей прямыми вызовами.

// Dynamic dispatch (slower for hot path):
func process(_ drawable: any Drawable) { drawable.draw() }
// Static dispatch after specialization:
func process<T: Drawable>(_ drawable: T) { drawable.draw() }
// Compiler may devirtualize and inline

Сравнительное измерение с XCTMeasure

Всегда проверяйте оптимизации с помощью сравнительных измерений XCTMeasure в наборе тестов, чтобы не допустить регрессий.

func testNormalizePerformance() {
  let data = Array(0..<100_000).map { Float($0) }
  measure {
    _ = normalize(data)
  }
}

Быстрая проверка

Что проверяет isKnownUniquelyReferenced(_:) при реализации копирования при записи?

Итоги урока

Сначала проводите профилирование с помощью Instruments. Используйте встроенный в Swift COW для коллекций; реализуйте его в пользовательских типах-значениях с помощью isKnownUniquelyReferenced. Используйте @inline(__always) для небольших функций на узких участках, @_specialize для узких мест в обобщённом коде и включайте WMO в сборках для выпуска. Проверяйте каждую оптимизацию сравнительными измерениями XCTMeasure.

Часто задаваемые вопросы

Урок «Оптимизация узких мест: COW, встраивание и специализация» бесплатный?

Да — полный текст урока «Оптимизация узких мест: COW, встраивание и специализация» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Оптимизация узких мест: COW, встраивание и специализация»?

Применяйте @inline, @_specialize и оптимизацию типов-значений на основе данных профилировщика. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Оптимизация узких мест: COW, встраивание и специализация»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы Instruments: Time Profiler
  2. Инструменты Allocations и Leaks
  3. Проверка главного потока и зависания
  4. Оптимизация узких мест: COW, встраивание и специализация
← Назад к Swift Academy