Как стать автором
Обновить

Комментарии 22

Поверхностно пробежал по коду.

Не учитывая что дисейбл компонента или СтопОллКорутинс по не осторожности все обломает, вас не смущает первый вызов всех методов сразу при добавлении тасков в StartTaskQueueClick? Которые, по идее, должны были бы вызываться позже после завершения предыдущего таска.

Pull Request Rejected :D
Не будет вызова одновременно всех методов) при добавлении задач, стартует только первая, последующие стартуют, когда завершиться предыдущая. Либо я вас не понял. А насчет выключения, ну это же просто менеджер, поэтому для этих целей заводишь отдельный MonoBehaviour, который только для Coroutine (его можно даже создать в TaskManager, чтобы в сцене случайно никто не убил).
Например:

_taskManager.AddTask(MoveFromTo(TargetImage.gameObject.transform, From.position, To.position, 2f));
_taskManager.AddTask(AlphaFromTo(TargetImage, 1f, 0f, 0.5f));

Не учитывая геттеров в параметрах, сначала вызывается MoveFromTo до первого «yield return ...» и возвращает IEnumerator, с которым вызывается и выполняется AddTask.
Сразу после этого вызывается AlphaFromTo, потом снова AddTask.
И уж где-то потом работают корутины.
Вы по опыту говорите или теоретически. Вот я сейчас запустил и проверил, вызывается все так как надо, не запускаются задачи, если не вызвано StartCorouine (даже до первого yield return)
Теоретически, после беглого просмотра, как написал выше.
Да, вы правы, если при добавлении таска корутины не стартуют, то методы не выполнятся. Не было времени углубится где там старт вызывается )
Ответ получил, вас это не смущает и ситуация разрулена правильно :)
Все ок и спасибо, я на самом деле когда писал, на автомате, вы сомнения зародили резонные и пришлось проверить)
Дисейбл компонента не влияет на выполнение корутин
ок, дисейбл объекта с компонентом :)
Хорошая статья, спасибо.
Я похожее делаю с использованием UniRx.
github.com/neuecc/UniRx

Но ваша обертка мне нравится больше. Она проще и понятнее.
Спасибо. UniRx это настоящая многопоточность, там не будет эффекта фризов основного потока Unity, которые возникают при наличии в Coroutine сильно прожорливых задач, но при этом всплывут другие неудобства. В общем инструмент под задачи)
Честно говоря, не очень.
Кроме общей неэффективности кода(каждый Таск — это две отдельные корутины, серьезно?), есть чисто архитектурные пробелы:
  • Таски не могут сообщить об ошибке
  • Таски не могут возвращать результат
  • Если бы Таски умели бы в вышеперечисленное, то неплохо было бы, чтобы внутри Таска можно было бы создавать другие таски дожидаться их выполнения и реагировать на результат/ошибку
  • Система приоритетов здесь вообще не к месту.


В общем и целом, следовало посмотреть на Task с async/await в современном c# и повторить их функционал на энумераторах — это вполне возможно, просто будет чуть менее аккуратно, чем с Task, так как он всё-таки имеет поддержку от компилятора.

async/await нет в Unity3d пока что, как минимум их нет для мобильных платформ. Две отдельные Coroutine только для IEnumerator, пишите CustomYieldInstruction обертку и будет одна. А в остальном, ну как бы да, но потому и называется простой менеджера задач, а не UniRx или что-то подобное.
async/await нет (точнее есть в 2017 в статусе experimental, а в 2018.1b12 .Net 4.6 уже дефолтный), но можно повторить его функционал на итераторах, немного криво-косо, но сносно (особенно если не добавлять возможность таскам возвращать значение)

Корутиной же можно обойтись одной на весь TaskManager.

К сожалению, в текущем виде статья — сборник вредных советов.
Ну напишите здесь пример, как можно это улучшить) а то как-то голословно все
К сожалению, я не могу приводить код по этой теме, потому что она слишком пересекается с тем, что я делаю для своего работодателя. Основная идея в том, чтобы перечислять IEnumerator/IEnumerable вручную и не создавать на каждый чих корутину. Обработку ошибок можно реализовать добавив в ITask свойство exception и заполнять его, если очередной MoveNext() выкинул исключение.

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

В таком случае я лучше UniRx заюзаю)). Смысл статьи в простом варианте, понятном для начинающих разработчиков на Unity, а не для продвинутых
Подход со свойством exception приведен вот в этом видео, в конце, где пишут StartCoroutine — с возвращаемым результатом. Жалко, когда я был новичком, не видел этого видео. Прикрепляю тут, надеюсь пригодится www.youtube.com/watch?time_continue=806&v=ciDD6Wl-Evk. Сам я, пришел из java и с JavaRx сразу пересел на UniRx, но в последнее время все больше пишу логики на yield-ах (т.е. корутинах), т.к. код на них мне легче сопровождать и читать. Ну и async/await вышли из беты и работают на unity ни для кого ни секрет. Они, в отличие от корутин, из коробки предоставляют удобные средства работы с exception и возвращаемым результатом
Про 2 Coroutine спасибо (поправил в тексте). Излишки когда режешь код свой для статьи.
На самом деле вариантов решения вашей проблемы куда больше.
Можно одновременно иметь 10к (Micro)Update.
blogs.unity3d.com/2015/12/23/1k-update-calls
More Effective Coroutines
assetstore.unity.com/packages/tools/animation/more-effective-coroutines-free-54975
JobQueue
wiki.unity3d.com/index.php/JobQueue
Thread Ninja
assetstore.unity.com/packages/tools/thread-ninja-multithread-coroutine-15717
И куча других разных ассетов со стора.
Но за статью спасибо, сам примерно тем же занимался до UniRx. И все же лучше будет вам перейти на UniRx. Удачи!
Спасибо за ссылки. Проблема не в UniRx, использовали, знаем. Но инструмент всегда под проекты и задачи. Когда были сложные проекты использовался UniRx, сейчас для нас этот инструмент это как промышленным прессом забивать гвозди. Ресурсы ограничены, нанимать людей которые будут понимать, что такое реактивное асинхронное программирование, да что там знать паттерн, который там используется, возможности нет. Статья в основном для Junior, на границе Middle программистов, чтобы с чего-то начинали и понимали, думали.
НЛО прилетело и опубликовало эту надпись здесь
1. С чего вы это решили, что я не понимаю, когда как в статье четко указано, про то как работают Coroutine и почему в других потоках нельзя использовать доступ UnityEngine.Object?
2. UniRx способен запускать, но не способен в этих потоках оперировать с объектами Unity, к чему вообще комментарий я не понял.
3. Очень интересно, теперь я буду знать, зачем я затеял это, спасибо.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории