Зачем нам нужен новый подход ?
Structured concurrency (далее SC) позволяет рассуждать о конкуретном вычислении используя специальные точки, позволяет узнать о разветвлениях, конкурентных вычислениях и увидеть результат вычислений, подобно тому, как работает блок условия if else
в синхронном коде.
Конкурентная задача начинается, когда вы используете async let
, создаете открепленную (detached) задачу или группу задач.
Задача возобновляются в точке приостановке (suspention point), обозначаемой await
.
Однако не все задачи являются структурированными.
important
Структурированные задачи создаются с помощью async let
и групп задач, а не структурированные — используя Task
и Task.detached
.
Структурированные задачи живут до конца области видимости, подобно локальным переменным и автоматически отменяются при выходе из области видимости. Такой подход даёт явно понять как долго задача должна жить.
note
Старайтесь, по возможности, использовать SC, вместо не структурированных задач (Unstructured).
О преимуществах SC вы можете прочитать ниже, а пока посмотрим на конкретный пример.
Представьте, что в нашем распоряжении кухня с несколькими шеф поварами, каждый из которых хочет приготовить суп. Приготовление супа состоит из нескольких шагов: нарезка ингридиентов, мариновка курицы, варка бульона и финальное приготовление. Некоторые задачи можно выполнить параллельно, а другие только в определенном порядке.
Посмотрим на нашу функцию приготовления makeSoup
.
Возможно вы захотите явно добавить неструктурированные задачи Task { … }
к вашим функциям и будете ожидать возвращения значения.
Это подразумевает, что задача будет выполняться конкуретно, но все же это не рекомендуемый способ использовать конкурентность в Swift.
Посмотрите на эту же функцию, но с использованием SC.
Поскольку мы знаем количество дочерних задач, мы можем использовать удобный синтаксис async let
.
В этом случае, задачи формируют структурированные отношения с родительской задачей. Чуть позже вы узнаете почему это важно.
makeSoup
вызывает несколько асинхронных функций, одна из которых нарезка ингридиентов chopIngridients(…)
, которая принимает список ингридиентов и использует taskGroup { … }
для конкрурентной нарезки.
Вы ознакомились с задачей по приготовлению супа. Самое время посмотреть как выглядит дерево иерархии (Task tree) этой задачи.
Дочерние задачи нашей функции выделены цветными квадратами. Стрелки указывают на отношения между родительскими и дочерними задачами.
Функция makeSoup
содержит 3 дочерние задачи:
- Нарезка ингридиентов
chopIngridients(🍍, 🥕, 🧅)
- Мариновка курицы
marinate(🍗)
- Варка бульона
boil broth
Функция chopIngridients(…)
использует taskGroup { … }
для создания дочерних задач для каждого ингридиента. Мы используем 3 ингридиента, поэтому будут созданы 3 дочерних задачи. Такие родитеские и дочерние отношения формируют дерево задач (task tree).
Про отмену задач сказано в другой главе.