Skip to content

Latest commit

 

History

History
194 lines (124 loc) · 19.5 KB

ThreadingConcurrency.md

File metadata and controls

194 lines (124 loc) · 19.5 KB

Grand Central Dispatch

libdispatch (aka GCD) – библиотека предоставляющая доступ к высокоуровневому API для конкурентного выполнения задач с управлением потоками за сценой. GCD абстрагируется от кода управления потоками и переносит его на системный уровень, предоставляя легкий API для определения задач и их выполнения в соответствующей очереди диспетчеризации. GCD работает на системном уровне, таким образом он может удовлетворить потребности всех запущенных приложений на девайсе, при этом управляя ресурсами эффективно.

Что такое dispatch queue?

Queue (очередь) представляет собой сущность, выполняющую задачи, поступающие на вход, на одном или множестве потоков. Очередь работает по принципу FIFO (first in, first out), таким образом первая задача на очереди будет первой направлена на выполнение на потоке.

Что такое main thread и его использование?

В iOS главный поток приложения - это очередь, состоящая из процессов. Главный поток должен использоваться для всех View, а элементы интерфейса не должны блокироваться выполняющимися задачами. Разработчику следует избегать функций, использующих главный поток для загрузки данных, изображений и т.д.

Существует 2 типа queue. Перечислите и расскажите.

flowchart TD
    A(2 queue)
    A --> Serial("serial");
    A --> Concurrent("concurrent");
Loading
  1. serial – выполняет задачи последовательно (поочередно). До тех пор, пока задача не будет выполнена, поток не приступит к выполнения следующей задачи в очереди.
  2. concurrent – выполняет задачи конкурентно. Задачи, поступающие в concurrent очередь, могут выполняться одновременно на разных потоках.

Объясните 3 GCD queues?

flowchart TD
    A("3 типа queues")
    A --> Main("Main");
    A --> Global("Global");
    A --> Custom("Custom");
Loading

GCD предоставляет 3 типа queues –

  1. Main queue: Serial queue – работает на main thread.
  2. Global queue: Concurrent queue – работает с разным приоритетом и доступен всей системе.
  3. Custom queue: Serial/ Concurrent queue.

Что такое Quality of Service?

Quality of Service (QOS) - это приоритет выполнения задачи в GCD. Если task имеет более высокий qos, чем другие, оно будет обработано раньше, чем task с более низким приоритетом.

QOS ранжируется от высшего к низшему:

  1. User Interactive: Задача, которая запускается в основном потоке, например, анимация или операции рисования.
  2. User Initiated: Задача, которую запускает пользователь и которая должна дать немедленные результаты. Эта задача должна быть завершена, чтобы пользователь мог продолжить работу.
  3. Utility: Задача, которая может занять некоторое время и не требует немедленного завершения. Аналогично индикаторам выполнения и импорту данных.
  4. Background: Данная задача не видна пользователю. Резервное копирование, синхронизация, индексирование и т.д.

Объясните data race?

Data Race - это ситуация, когда две инструкции из двух разных потоков пытаются получить доступ к одному и тому же участку памяти, при это один из этих доступов на запись и между ними нет никакой синхронизации.

Объясните race condition?

Это семантическая ошибка, возникающая во времени или порядке событий, которая приводит к неверному поведению программы. Race Condition может быть вызвана Data Race, но может быть вызвана и другими причинами. Одним из решений может быть NSLock()

Объясните deadlock?

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

Что такое priority inversion?

Priority inversion (инверсия приоритетов) - это критическое состояние в потоках, когда поток с низким приоритетом блокирует выполнение потока с высоким приоритетом и делает назначенные приоритеты бессмысленными для потока. Такая ситуация возникает, когда поток с более низким приоритетом захватил какой-то общий ресурс и использует его, тем самым поток с высоким приоритетом не может использовать этот ресурс.

Объясните NSOperation?

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

Объясните ThreadPool?

ThreadPool — пул потоков, которые повторно используют фиксированное число потоков для выполнения конкретной задачи.

Что такое Semaphore?

Semaphore предоставляет нам возможность контролировать доступ нескольких поток к общему ресурсу. Семафор состоит из очереди потоков и счетчика значений. Счетчик значений используется семафором, чтобы решить, должен ли поток получить доступ к общему ресурсу или нет. Счетчик значений изменяется при вызове методов signal() или wait():

class DispatchSemaphore : DispatchObject {
  func signal() -> Int { } // Signals (increments) a semaphore.
  func wait() { } // Waits for, or decrements, a semaphore.
}

Structured Concurrency

Что такое Task?

Task - юнит асинхронной работы, в котором выполняется async функция:

@frozen struct Task<Success, Failure> where Success : Sendable, Failure : Error

Task позволяют создавать конкурентное окружение из не-конкурентных методов с помощью вызова async/await. Задача выполняется немедленно после объявления и не требует явного запуска. Задачи имеют приоритет, их можно отменять, и они могут находиться в трёх состояниях - приостановленные, выполняющиеся и завершенные. Могут быть структурированными и неструктурированными.

Расскажите о Task priority

За приоритеты в Task отвечает структура TaskPriority, которая содержит следующие приоритеты:

flowchart TD
    A("Task Priority")
    A --> high("high");
    A --> medium("medium");
    A --> low("low");
    A --> userInitiated("userInitiated");
    A --> background("background");
    A --> utility("utility");
Loading
  1. high
  2. medium
  3. low
  4. userInitiated
  5. background
  6. utility

Дочерние таски автоматически наследуют приоритет родительской. Detached таски, созданные методом detach(priority:operation:), не наследуют приоритет, поскольку они не присоединены к текущей задаче.

Расскажите о TaskGroup

TaskGroup — группа, содержащая динамически созданные дочерние таски:

@frozen struct TaskGroup<ChildTaskResult> where ChildTaskResult : Sendable

Для создания группы, вызовите метод withTaskGroup(of:returning:body:). Не используйте группу вне области Task. В большинстве случаев, система типов Swiftне позволит выйти из области видимости task group, поскольку добавление дочерней задачи в task group является операцией мутации, которые не могут быть выполнены из конкурентного контекста.

Что такое actor?

actor — reference type, который защищает доступ к изменяемому состоянию и объявляется с помощью ключевого слова actor. Тип данных, который можно безопасно использовать в конкурентной среде. Содержит следующие характеристики:

  1. Имеют собственное изолированное состояние.
  2. Может содержать логику для изменения собственного состояния.
  3. Может общаться с другими участниками только асинхронно (через их адреса).
  4. Может создавать других дочерних акторов (в данном случае нас это не особо волнует).

Расскажите о ключевом слове await

await — это специальная пометка, которая говорит о том, что в этом месте может быть suspension point.

Suspension points(точки приостановки) – динамическая концепция всей программы, которая гласит: существуют места, которые могут фактически приостанавливать выполнение задачи и оставить поток.

Potential suspension points - are the static, conservative, function-local view of suspension points: they're the points in the function where a suspension could potentially occur and therefore the function ought to be prepared to abandon the thread. Any dynamic suspension point is always "inside" a potential suspension point from the perspective of every async function on that task: all of the outer functions must be awaiting an asynchronous call, and the innermost function must be awaiting at the actual dynamic suspension point. From all of those functions' local perspectives, the exact reason for the suspension (which may be N levels of call deep) is much less important than the fact that a suspension is possible at that point in their execution.