Comments 7
Спасибо, хорошая статья, узнал кое-что новое.
Хотел бы дополнить две вещи - на вопросы в заголовке статья не ответила:
1 - Что такое корутины?
Это механизм для запуска асинхронных методов, которые позволяют удобно описывать длительные (в несколько кадров) операции. Это удобно для процедурных анимаций.
2 - При чем тут IEnumerator?
IEnumerator - это стандартная реализация паттерна "итератор" в C#, которая содержит синтаксический сахар для хранения состояния.
Unity использует этот механизм в необычных целях из-за сахара - состояние итератора используется как состояние асинхронной операции.
Правильной функциональностью для этого в современном C# является механизм асинхронных функций с async/await (он буквально для этого предназначен), который в определенном смысле работает похоже. Видимо в Unity создали корутины когда async/await не было.
Соответственно можно найти библиотеки для реализации корутин на async/await
Искренне рад, что вам понравилась статья!
Добавлю ваши замечания, но с небольшими корректировками:
Корутины не являются асинхронными, они выполняются в основном потоке приложения, в том же, что и отрисовка кадров, инстансирование объектов и т.д., если заблокировать поток в корутине, то остановится все приложение, корутины с асинхронностью использовали бы "IAsyncEnumerator", который Unity не поддерживает. Но вы правы, что корутина позволяет растянуть выполнение на несколько кадров, что бы не нагружать 1 кадр большими вычислениями. Unity предоставляет тип UnityWebRequest для Http запросов, которые можно выполнять "асинхронно" в несколько кадров, что может показаться "асинхронностью", на самом деле же это обертка над нативным асинхронным HttpClient, которая предоставляет некоторую информацию синхронно, по типу поля isDone, которое отображает - закончился ли запрос или еще ожидается ответ, но сам запрос идет асинхронно.
Поэтому Unity корутины, в рамках программирования, не реализуют асинхронность.
async\await существует с C# 5, которая, согласно гуглу, вышла в 2012 году, вряд ли за 10 лет команда Unity не обновила бы свой движек, учитывая, что появление async\await было самым главным событием для языка, поэтому смысл корутин в другом, а именно - разделить выполнение на несколько кадров в основном потоке, что написано в документации.
Применение для асинхронных корутин мне сложно придумать, если есть Async\Await.
Я имел в виду асинхронность в широком смысле - корутины в таком случае вполне асинхронный механизм.
Насколько я понимаю, механизм async/await не обязывает использовать многопоточность (хотя предназначен в том числе для ожидания выполнения задач в других потоках и простой их синхронизации в основной)
В node.js операции асинхронные, хотя работают в контексте одного потока (конкретные io операции при этом могут выполнятся и в других потоках, зависит от реализации)
Существует уже несколько библиотек, реализующих функциональность корутин на async/await
Они просто предоставляют готовые асинхронные методы для главного потока, имитирующие поведение корутин - WaitForSeconds или WaitForNextFrame
https://habr.com/ru/post/652483/
Только они не стандартные и не включены в поставку от самой Unity, хотя по идее, являются более правильным сахаром для этого.
Стоило бы упомянуть про async в Unity
async/await - намного лучше. Одна проблема - прервать нельзя, просто не реагирует(
Можно через CancellationToken. https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.cancellationtoken?view=net-6.0
А так корутины и асинхронность хороша под разные задачи, нельзя сказать, что что-то лучше всегда.
Unity: Что представляет из себя Coroutine и зачем там IEnumerator