Логично, если таково условие в договоре. А если нет такого в договоре - не логично. Несколько не в тему. У меня вот, Мегафон просто удалил мой номер, что был 10+ лет, ссылаясь на какую-то муть и закон о связи. Даже без возможности восстановления. С учётом того что вся привязка и данные идут через номер мобильного - печально(
Язык полный. С ним можно всё реализовать из чего угодно. Да, можно сделать костыль, как в 3 пункте. И с генератором(фабрикой), что будет генерить объекты при повторном вызове, таким образом обойти ограничение и на множественные вызовы. Весь код сведётся к ~ такому:
private Task<object> _requestResult; private Task<object> MakeRequestAsync() { return _requestResult == null ? _client.LongServerRequestAsync() : _requestResult; } Кстати, памяти он выделит ~ столько же. Переиспользования тут не будет - будут создаваться отдельные UniTask структуры или иногда будут происходить ошибки
Сами ограничения такие же как у ValueTask. Их уже повторял я, и сам автор плагина, и в документации msdn есть. Вот даже статья когда нужно применять ValueTask(UniTask).
Рабочий пример не дам - он большой. Но можете сами дописать этот пример упрощённый для стартовой инициализации и загрузки. Методы - инициализация сервисов, сцен, загрузка контента, сетевые запросы, включая авторизацию, группы и прочие данные из разных мест, да и вообще всё, что нужно для старта игры. Task<SomeObj> task1 ; // и так до, скажем, N = 10 void LoadAllServices(){ task1 = InternalMethod1(); // И так все N } async Task<SomeObj> InternalMethod1(){ await Task.Yield(); return await Method1(task2, task3); // MethodN с передачей случайного набора задач, но не приводящие к циклической зависимости // конечно, внутри метода эти задачи ожидаются} PS: тут мне подсказали, что Task-и всё ещё не дружат с WebGL. UniTask работает. ValueTask не понятно.
Мне так же интересно услышать об опыте других людей) Я ранее так же использовал первые версии UniTask или аналоги(не помню), ещё до того как async/await появился в языке в Unity. И тогда же опробовал в небольшим коммерческом проекте и уже тогда это было на много лучше других решений, хотя и очень узко применимо. Сейчас единственной проблемой Task .Net в Unity считаю отсутствие стека при вызове от UnitySyncronizationContext. Её так и не получилось решить. Но и в этих статьях нашёл парочку особенностей, что когда-нибудь упростит мне код) Всё остальное, что я тут видел или о чём слышал, я, пожалуй, уже пробовал.
Оставляете начальную реализацию и Меняете реализацию сразу? Нужно же всё в одном. Множество запросов, множество задач, которые хотят использовать эти данные, а их использование зависит от других задач. И всё это так, чтобы не сильно париться об очерёдности. Концептуально другое использование.
Я не вижу смысла в использовании UniTask повсеместно из-за его ограничений. Это "оптимизация" за счёт функционала. Преимущества по сравнению с TaskValue пока не ясны, ещё посмотрю. В том коде, что я видел тут, async/await выступает почти как отдельный инструмент, очень ограничено в плане возможностей. Я весь код, зависящий от внешней среды или времени выполнения, оборачиваю в Task-и, а логика в целом остаётся никак не ограничена и не содержит огромное кол-во сопроводительного кода. Она остаётся очень легкой для понимания. И это даёт что-то вроде синергетического эффекта, где очень просто можно получить что надо, без обёрток и извращений как с _longServerRequestTask
Concurrency? Мне об этом вообще почти не надо думать -- достаточно чисто умозрительно заключить, что не получился Уроборос. И если так, то как ни сделаю, всё равно получится рабочий код. В этом и есть прелесть async/await. Это не просто замена корутинам или промисам. Это то, что позволяет избавится от кучи кода и проблем синхронизации. Просто забыть о мозголомных вычислениях, и ухищрениях с примитивами. Так ещё при этом получить хорошую производительность, возможность простого разделения логики и UI, или, к примеру, предикшены поставить без дополнительных ухищрений.
Ничего против UniTask для работы с готовыми эмиттерами не имею - их всё равно не в Unity, а значит альтернативу надо или делать самому или брать что подойдёт. Что есть все основные функции юнити, а может и вообще всё - это хорошо. Если нужно их использовать в проекте, и особенно в нагруженной части - вообще отлично) Но для более широкого использования нужен полный функционал.
PS: Ну и генерится всё же будут объекты, а не классы)
await WaitAsync().ConfigureAwait(false); На деле способов много, все даже не упомню. Разница в том, что Task.Run сразу запускает задачу через менеджер, а не после ожидания. Это является правильным способом именно для запуска с распределением задач по потокам. _longServerRequestTask Но это же просто обход ограничения по применению. А если нужно множество запросов? Выходит прямо таки одноразовый сетевой сервис. А если его сделать многоразовым, то придётся генерить классы. А если ожидать данные с одного запроса нужно из нескольких мест и мы не контролируем момент получения результата и запроса? Т.е. обычное ожидание Task<Player> player = Request.Send(); c нуждой в ожидании из нескольких мест(к примеру, нескольким объектам нужно имя пользователя), а тем более из других задач, с не ясным временем когда понадобится player, то как делать? Вместо обычного await player придётся городить весьма не мало кода, теряя, собственно ожидание. Либо городить фабрику ожидающую и отдающую результат. Причём, накладные расходы будут значительно выше.
Asynс изначально везде добавляли к дублирующим методам - string Download() и Task<string> DownloadAsync(). Но сейчас нет часто нет дублирующих и тип сразу подсказывает среда разработки. А раз уникальной инфы это не несёт, то зачем оно?
Не пользуюсь этими плагинами, только нативный C# async/await/Task и т.д. Ошибки по 1-2 пункту есть. По крайней мере у меня это не выполняется, да и не сходится с документацией msdn.
2) private void Awake(){ Debug.Log("Awake_start"); Method(); Debug.Log("Awake_end");} private async void Method(){ Debug.Log("Method_start"); Task t = Task.CompletedTask; await t; Debug.Log("Method_end");} Тут выведет: Awake_start Method_start Method_end Awake_end Если задача не завершена, т.е. случится ошидание, то выведет: Awake_start Method_start Awake_end Method_end Всё потому, что код до ожидания выполняется синхронно деля async методы AwakeиMethod на части, где ожидание - разделитель. Условно, GOTO в первом случае перекидывает на 2 часть Method, переключения не происходит. А в случае ожидания в Method, сразу на вторую часть Awake. Вторая же часть Method будет запущена через UnitySynchronizationContext, в порядке очереди player loop(Start,Awake,Update и прочие).
1) Всё выполняется в основном потоке, если правильно запускать. В принципе, так же как UniTask. Task t = SomeTask(); await t; запустит всё, включая внутренности SomeTask в основном потоке. И даже после ожидания продолжится выполнение так же в основном потоке. В случае без ожидания мы просто не получим сообщений(дебаг, ошибки), но выполнение будет так же в основном потоке. До какой-то там версии это было не так, но уже давно всё работает через UnitySynchronizationContext. Со всеми + и, к сожалению, - тоже. Потому как логи после ожидания идут от UnitySynchronizationContext, а не с начала вызова, что очень печально, ведь без UnitySynchronizationContext вполне удавалось получать логи от начала вызова.
Для запуска вне основного потока надо использовать Task.Run(). Так называемая "настоящая асинхронность" потоков будет работать только в этом случае. Разница прежде всего в том, что вне основного потока мы не можем выполнять методы с обращением к нативному коду, к примеру, работать с Transform.SetPositions(). Но весь чисто C# код доступен. Ну и так же берегитесь async void, который вызывает другой async void. В этом случае работа становится несколько непредсказуемой. К примеру могут сообщаться ошибки, но пропасть обычные логи, а может наоборот, ну или вообще никаких сообщений в редакторе не будет(в файлах логов будут).
Asa limitation, all UniTask objects cannot await twice, as they automatically return to the pool when the await completes. Ну и продолжение с конкретикой. Вот это надо всегда говорить. Совсем не явная штука, которая ограничивает UniTask в использовании, приводя их не более чем к аналогу корутин, промисов с некоторыми улучшениями.
Вообще, можно сделать свой объект для ожидания с CTS на Update и/или с проверкой на запуск и состояние объекта. Это был бы очень полезный функционал, жаль, что Unity по факту не поддерживает всё это из коробки. Как было в далёкой 1(3) версии, так всё и осталось. Но плюсы для меня перевешивают даже эти минусы, а CTS на деле не так уж и часто нужен, почти всегда можно обойтись без него.
Насчёт OnDestroy, не помню такого, чтобы не было вызова, если объект действительно уничтожался. При краше, возможно, но в таком случае уже и не важно. Основной поток и при ошибке, и при установке не умирает. Он продолжает работать и не в плеймоде.
Основной плюс не в замене корутин. Это вообще мелочь, которая нужна для раскрытия всего потенциала. С async/await и Task можно легко и просто делать сложные вещи, которые без этого требуют кучу кода и много расчётов, при этом ещё и писать легко читаемый код. Управление загрузкой(вообще, не только файлов), управление стейтами, понятное и простое разделение осуществляемых действий(задач) на Task-и. А так же легкая и непринуждённая их комбинация с минимальными изменениями в коде. Даже то, что промисами делалось не даёт такой простой работы и содержит кучу скобочек, вложенных методов, да и всякого левого кода. Код стал вновь как на лабе в универе, легко читаем и джуном. Правда только в области логики, потому как сопровождать и оборачивать юнити приблуды нужно. Но весь бойлерплейт отделён от логики. Если бы Unity поддерживали таски по умолчанию во всех компонентах, то вообще сказочно вышло бы)
Я пришёл к тому, что стоит использовать Animator и не пилить велосипеды. Вариативность высокая, анимации настроить можно и художникам отдать и не трогать программистов по мелочам. С Task подружил и теперь могу использовать это в игре для ожидания. Хотя, было и не просто из-за того, что аниматор не даёт использовать имена стейтов. Впрочем, никогда не использовал для этого корутин и не вижу в этом +. Видел то же на дотвине, довольно не плохо и всё через код - быстро. Минус только в том, что для изменений всегда нужен прогер.
Эффективен он в принципе, всегда. Не за счёт производительности, а за счёт понятных и простых конструкций в коде и их вариативности использования. Корутины - это даже не прошлый век, а позапрошлый или вообще от мамонтов. До них ещё были промисы(как в дотвине) и эвенты(как замена колбекам). И всё это решало одну и ту же проблему ожидания процессов и их компоновки, и в целом использования. Но для понимания этого стоит ознакомится с ними в принципе, даже вне Unity.
Корутины могут быть быстрее, но если очень нужна производительность, то стоит работать с самим подходом - получать пул объектов, обрабатывать в циклах и т.п. Для одиночных сложных операций оверхед не существенен даже на старых мобилках и ТВ приставках. Для чего-то на уровне железа всегда циклы и массивы, ну или для того же с удобством сейчас это ECS и всё такое(таких проектов и не знаю, где это прям абсолютно нужно). Корутины в таком случае могут быть медленее в десятки раз, а значит и нет смысла с ними работать в указанных условиях. А, ну и сам Update у объекта не стоит забывать. Часто вместо него используют корутины, что так же не правильно и приводит к проблемам. Везде можно использовать либо Task, либо Update.
Пункты 1-6 работают и при стандартном Task. Пункт 7 спорный. При стандартном Task лог начинается от места старта или ожидания(SyncContext), если последнее произошло. И это отлично, если с UniTask работает лог даже при ожидании - крайне полезно получать лог как при синхронном выполнении. Только по примеру не ясно, так ли это?
Однако, не всё так хорошо и 8 я назову скорее отрицательным и ставящим крест на UniTask для повсеместного использования. Поначалу я думал, что прошлый опыт использования оказался негативным случайно. Но читая про оптимизацию, понял, что нет. Как часто и бывает, получив некоторое ускорение быстродействия порезали ошибки и НЕЯВНО привели к ситуации с багами. Задобали тупые картинки с супералгоритмами по типу - вырежу половину функционала и получу буст! (и забывают хотя бы мелким шрифтом прописать условия при которых он будет, но которых может и на пару страниц текстом набраться)
The following operations should never be performed on a ValueTask instance:
* Awaiting the instance multiple times. * Calling AsTask multiple times. * Using .Result or .GetAwaiter().GetResult() when the operation hasn’t yet completed, or using them multiple times. * Using more than one of these techniques to consume the instance.
If you do any of the above, the results are undefined.
Всего то сделал из мультитула заточку. За то вес уменьшился! Да по факту же вырезана основная прелесть async/await!
Суть не в последовательных действиях, с этим и промисы справлялись не плохо, а в применении ожидания одного действия в разных местах. Когда делаешь загрузку ресурсов для игры - плевать на выделение даже мегабайта памяти - её и так выделяется много. А вот сделать менеджер загрузки ресурсов с ожиданием цепочек действий, их агрегацией, да ещё асинхронно по готовности, да буквально за пол часа сделать всё это - очень круто. Сделать загрузку плагинов с зависимостями просто поставив в методы Load ожидание окончание загрузки требуемых плагинов и запустив весь десяток-другой методов загрузки, не заботясь вообще об очерёдности. К примеру IAP, плагины издателя, Ads требуют UnityServ; а плагин издателя ещё и IAP, и FB; а FB нужны ключи сервера и IAP; ну и т.д.).
Про аллокацию так же замечу, что на структуру тоже выделяется память, тоже в неё пишется. Это ни разу не волшебная пуля и минусы в этом тоже есть. Здесь всё аналогично пулу.
Я имел ввиду изменения, которые позволяют увеличить возраст, в котором смогут плодить детей уже обустроенные в жизни люди. Сейчас же при увеличении возраста падает здоровье в целом, либидо, фертильность в целом, а так же частота успешных зачатия, вынашивания, родов(с учётом попыток и успехов). Все эти факторы фактически являются возрастными и их "решение" вполне может влиять на продолжительность жизни.
Женщина которая доживает до 18 лет и с генетически обусловленным желанием иметь как можно больше детей вполне может вносить больше вклада в распространение собственных генов, чем женщина которая дожила до 120 лет и была способна забеременеть вплоть до 60 лет, если они живут в современном цивилизованном обществе, где дети, о которых не особо заботились, всё равно выживают и могут иметь собственных детей. Это уже спор у кого больше, т.е. параллельно может существовать несколько успешных стратегий. Но похоже, всё работает иначе. Падает рождаемость везде. Но, пока, что не везде это приняло такой же большой масштаб. Никто не считает сколько таких женщин умерло в следствие плохой медпомощи, невозможности прокормить детей? дети, о которых не особо заботились, всё равно выживают и могут иметь собственных детей - никто не проверял, правда ли это возможно с сохранением фертильности. Как минимум, нужны ресурсы на вынашивание, последующее лечение и повтор. Сколько не переживут, либо потеряют фертильность в процессе такой тактики? Государство на деле вот ни черта не торопится брать на себя ответственность, а наоборот - всеми силами скидывает на родителей, как в РФ, так и во всех других странах. Бесплатные школы - это ни разу не достаточны. Они могут только компенсировать новые затраты. А уголовное преследование за оставление в опасности/халатность по отношению к детям очень сильно добавляют хлопот в городской жизни. Новоиспечённую мать скорее посадят, чем помогут ей.
Сам узнал о статье на хабре ~2-6 лет назад. Не найду. Там учитывали фактор благосостояния, хотя могу ошибаться. Рост продолжительности, на сколько помню был не большой, но статистически значимый.
Если прям супер-полезная мутация, то достаточно несколько поколений. 4 группа крови вон 1 тысячу лет как) А с 1 до 2 основная часть сменилась за 5к лет в европейском.
В масштабах десятков тысяч лет заметны уже большие изменения. Но это возможно всего ~1% от всех изменений, т.к. большую часть изменений мы сейчас можем узнать только статистически по останкам и внешним предположениям . Какова частота закрепляющихся изменений на уровне генов, на сколько знаю, так и не вычислили. У некоторых бактерий это дни или всего ~10 поколений, а порой и того меньше.
Помимо поколений, есть ещё и фактор изменчивости. Сейчас и людей на много больше, и изменчивость на много выше. Потому как ранее закрытые критическими генами пути эволюции сейчас стали открыты в силу развития медицины и изменения формы существования.
Этот вариант больше похож на проигрыш некоторых стратегий. Т.е. как такового увеличения он не даёт - только отрезает всяких чайлдфри, тем самым увеличивая долю иных стратегий.
Есть и другой вариант - увеличение продолжительности жизни вместе с увеличением эффективного возраста фертильности. И, что интересно, по некоторым исследованиям, у поздних детей продолжительность жизни немного выше.
С чего вы взяли, это десятки тысяч лет? Эволюция и сейчас идёт. Только все параметры мы не можем объективно оценить. Впрочем, даже довольно заметные отличия, вроде отсутствующей мышцы/связки не всегда замечаются.
И это при том, что влияние на выживаемость оказывается огромное. Сейчас горизонт возможностей для эволюции как никогда огромен и всё больше расширяется, что сильно ускоряет эволюцию.
Как-то делал домики для детский игры, вся цветовая схема вышла на 128 байт + сам домик на 128 байт(по сути векторная графика, в упрощённом виде/формате). И домики те были на много сложнее менюшек. Так, к примеру, можно менюшку виндового окна сделать, причем, с прозрачностью, неровными краями. Немного сложнее и раза в 1.5 больше по весу будет оптимизированный 9-slice. А это позволит выводить картинку менюшек как в играх(правда, выглядеть будет хуже, как с низкокачественной графикой).
Самое тяжёлое будет со шрифтами - они много весят даже в жёстком монохроме. А программные шрифты тянут программу, что тоже занимает не мало места. Так выйдет, что весить каждый символ наверняка будет даже больше домика.
Логично, если таково условие в договоре. А если нет такого в договоре - не логично. Несколько не в тему. У меня вот, Мегафон просто удалил мой номер, что был 10+ лет, ссылаясь на какую-то муть и закон о связи. Даже без возможности восстановления. С учётом того что вся привязка и данные идут через номер мобильного - печально(
А написать надо чисто логику или код?
Язык полный. С ним можно всё реализовать из чего угодно. Да, можно сделать костыль, как в 3 пункте. И с генератором(фабрикой), что будет генерить объекты при повторном вызове, таким образом обойти ограничение и на множественные вызовы. Весь код сведётся к ~ такому:
private Task<object> _requestResult;
Кстати, памяти он выделит ~ столько же. Переиспользования тут не будет - будут создаваться отдельные UniTask структуры или иногда будут происходить ошибкиprivate Task<object> MakeRequestAsync()
{
return _requestResult == null ? _client.LongServerRequestAsync() : _requestResult;
}
Сами ограничения такие же как у ValueTask. Их уже повторял я, и сам автор плагина, и в документации msdn есть. Вот даже статья когда нужно применять ValueTask(UniTask).
Рабочий пример не дам - он большой. Но можете сами дописать этот пример упрощённый для стартовой инициализации и загрузки. Методы - инициализация сервисов, сцен, загрузка контента, сетевые запросы, включая авторизацию, группы и прочие данные из разных мест, да и вообще всё, что нужно для старта игры.
Task<SomeObj> task1 ; // и так до, скажем, N = 10
PS: тут мне подсказали, что Task-и всё ещё не дружат с WebGL. UniTask работает. ValueTask не понятно.void LoadAllServices(){
task1 = InternalMethod1(); // И так все N }
async Task<SomeObj> InternalMethod1(){
await Task.Yield();
return await Method1(task2, task3);
// MethodN с передачей случайного набора задач, но не приводящие к циклической зависимости
// конечно, внутри метода эти задачи ожидаются}
Мне так же интересно услышать об опыте других людей) Я ранее так же использовал первые версии UniTask или аналоги(не помню), ещё до того как async/await появился в языке в Unity. И тогда же опробовал в небольшим коммерческом проекте и уже тогда это было на много лучше других решений, хотя и очень узко применимо.
Сейчас единственной проблемой Task .Net в Unity считаю отсутствие стека при вызове от UnitySyncronizationContext. Её так и не получилось решить. Но и в этих статьях нашёл парочку особенностей, что когда-нибудь упростит мне код) Всё остальное, что я тут видел или о чём слышал, я, пожалуй, уже пробовал.
Оставляете начальную реализациюиМеняете реализациюсразу?Нужно же всё в одном. Множество запросов, множество задач, которые хотят использовать эти данные, а их использование зависит от других задач. И всё это так, чтобы не сильно париться об очерёдности. Концептуально другое использование.
Я не вижу смысла в использовании UniTask повсеместно из-за его ограничений. Это "оптимизация" за счёт функционала. Преимущества по сравнению с TaskValue пока не ясны, ещё посмотрю. В том коде, что я видел тут, async/await выступает почти как отдельный инструмент, очень ограничено в плане возможностей. Я весь код, зависящий от внешней среды или времени выполнения, оборачиваю в Task-и, а логика в целом остаётся никак не ограничена и не содержит огромное кол-во сопроводительного кода. Она остаётся очень легкой для понимания. И это даёт что-то вроде синергетического эффекта, где очень просто можно получить что надо, без обёрток и извращений как с
_longServerRequestTaskConcurrency? Мне об этом вообще почти не надо думать -- достаточно чисто умозрительно заключить, что не получился Уроборос. И если так, то как ни сделаю, всё равно получится рабочий код. В этом и есть прелесть async/await. Это не просто замена корутинам или промисам. Это то, что позволяет избавится от кучи кода и проблем синхронизации. Просто забыть о мозголомных вычислениях, и ухищрениях с примитивами. Так ещё при этом получить хорошую производительность, возможность простого разделения логики и UI, или, к примеру, предикшены поставить без дополнительных ухищрений.
Ничего против UniTask для работы с готовыми эмиттерами не имею - их всё равно не в Unity, а значит альтернативу надо или делать самому или брать что подойдёт. Что есть все основные функции юнити, а может и вообще всё - это хорошо. Если нужно их использовать в проекте, и особенно в нагруженной части - вообще отлично) Но для более широкого использования нужен полный функционал.
PS: Ну и генерится всё же будут объекты, а не классы)
await WaitAsync().ConfigureAwait(false);На деле способов много, все даже не упомню. Разница в том, что Task.Run сразу запускает задачу через менеджер, а не после ожидания. Это является правильным способом именно для запуска с распределением задач по потокам.
_longServerRequestTaskНо это же просто обход ограничения по применению. А если нужно множество запросов? Выходит прямо таки одноразовый сетевой сервис. А если его сделать многоразовым, то придётся генерить классы. А если ожидать данные с одного запроса нужно из нескольких мест и мы не контролируем момент получения результата и запроса?
Т.е. обычное ожидание
Task<Player> player = Request.Send();c нуждой в ожидании из нескольких мест(к примеру, нескольким объектам нужно имя пользователя), а тем более из других задач, с не ясным временем когда понадобитсяplayer, то как делать? Вместо обычногоawait playerпридётся городить весьма не мало кода, теряя, собственно ожидание. Либо городить фабрику ожидающую и отдающую результат. Причём, накладные расходы будут значительно выше.Asynс изначально везде добавляли к дублирующим методам -
string Download()иTask<string> DownloadAsync(). Но сейчас нет часто нет дублирующих и тип сразу подсказывает среда разработки. А раз уникальной инфы это не несёт, то зачем оно?Не пользуюсь этими плагинами, только нативный C# async/await/Task и т.д. Ошибки по 1-2 пункту есть. По крайней мере у меня это не выполняется, да и не сходится с документацией msdn.
2)
private void Awake(){Debug.Log("Awake_start");
Method();
Debug.Log("Awake_end");}
private async void Method(){
Debug.Log("Method_start");
Task t = Task.CompletedTask;
await t;
Debug.Log("Method_end");}
Тут выведет:
Awake_start Method_start Method_end Awake_end
Если задача не завершена, т.е. случится ошидание, то выведет:Awake_start Method_start Awake_end Method_end
Всё потому, что код до ожидания выполняется синхронно деля async методыAwakeиMethodна части, где ожидание - разделитель. Условно, GOTO в первом случае перекидывает на 2 частьMethod, переключения не происходит. А в случае ожидания вMethod, сразу на вторую частьAwake. Вторая же частьMethodбудет запущена через UnitySynchronizationContext, в порядке очереди player loop(Start,Awake,Update и прочие).1) Всё выполняется в основном потоке, если правильно запускать.
В принципе, так же как UniTask.
Task t = SomeTask(); await t;запустит всё, включая внутренностиSomeTaskв основном потоке. И даже после ожидания продолжится выполнение так же в основном потоке. В случае без ожидания мы просто не получим сообщений(дебаг, ошибки), но выполнение будет так же в основном потоке.До какой-то там версии это было не так, но уже давно всё работает через UnitySynchronizationContext. Со всеми + и, к сожалению, - тоже. Потому как логи после ожидания идут от UnitySynchronizationContext, а не с начала вызова, что очень печально, ведь без UnitySynchronizationContext вполне удавалось получать логи от начала вызова.
Для запуска вне основного потока надо использовать Task.Run().
Так называемая "настоящая асинхронность" потоков будет работать только в этом случае.
Разница прежде всего в том, что вне основного потока мы не можем выполнять методы с обращением к нативному коду, к примеру, работать с Transform.SetPositions(). Но весь чисто C# код доступен.
Ну и так же берегитесь async void, который вызывает другой async void. В этом случае работа становится несколько непредсказуемой. К примеру могут сообщаться ошибки, но пропасть обычные логи, а может наоборот, ну или вообще никаких сообщений в редакторе не будет(в файлах логов будут).
As a limitation, all UniTask objects cannot await twice, as they automatically return to the pool when the await completes. Ну и продолжение с конкретикой.
Вот это надо всегда говорить. Совсем не явная штука, которая ограничивает UniTask в использовании, приводя их не более чем к аналогу корутин, промисов с некоторыми улучшениями.
Вообще, можно сделать свой объект для ожидания с CTS на Update и/или с проверкой на запуск и состояние объекта. Это был бы очень полезный функционал, жаль, что Unity по факту не поддерживает всё это из коробки. Как было в далёкой 1(3) версии, так всё и осталось. Но плюсы для меня перевешивают даже эти минусы, а CTS на деле не так уж и часто нужен, почти всегда можно обойтись без него.
Насчёт OnDestroy, не помню такого, чтобы не было вызова, если объект действительно уничтожался. При краше, возможно, но в таком случае уже и не важно.
Основной поток и при ошибке, и при установке не умирает. Он продолжает работать и не в плеймоде.
Основной плюс не в замене корутин. Это вообще мелочь, которая нужна для раскрытия всего потенциала. С async/await и Task можно легко и просто делать сложные вещи, которые без этого требуют кучу кода и много расчётов, при этом ещё и писать легко читаемый код. Управление загрузкой(вообще, не только файлов), управление стейтами, понятное и простое разделение осуществляемых действий(задач) на Task-и. А так же легкая и непринуждённая их комбинация с минимальными изменениями в коде. Даже то, что промисами делалось не даёт такой простой работы и содержит кучу скобочек, вложенных методов, да и всякого левого кода. Код стал вновь как на лабе в универе, легко читаем и джуном. Правда только в области логики, потому как сопровождать и оборачивать юнити приблуды нужно. Но весь бойлерплейт отделён от логики. Если бы Unity поддерживали таски по умолчанию во всех компонентах, то вообще сказочно вышло бы)
Я пришёл к тому, что стоит использовать Animator и не пилить велосипеды. Вариативность высокая, анимации настроить можно и художникам отдать и не трогать программистов по мелочам. С Task подружил и теперь могу использовать это в игре для ожидания. Хотя, было и не просто из-за того, что аниматор не даёт использовать имена стейтов. Впрочем, никогда не использовал для этого корутин и не вижу в этом +. Видел то же на дотвине, довольно не плохо и всё через код - быстро. Минус только в том, что для изменений всегда нужен прогер.
Эффективен он в принципе, всегда. Не за счёт производительности, а за счёт понятных и простых конструкций в коде и их вариативности использования. Корутины - это даже не прошлый век, а позапрошлый или вообще от мамонтов. До них ещё были промисы(как в дотвине) и эвенты(как замена колбекам). И всё это решало одну и ту же проблему ожидания процессов и их компоновки, и в целом использования. Но для понимания этого стоит ознакомится с ними в принципе, даже вне Unity.
Корутины могут быть быстрее, но если очень нужна производительность, то стоит работать с самим подходом - получать пул объектов, обрабатывать в циклах и т.п. Для одиночных сложных операций оверхед не существенен даже на старых мобилках и ТВ приставках. Для чего-то на уровне железа всегда циклы и массивы, ну или для того же с удобством сейчас это ECS и всё такое(таких проектов и не знаю, где это прям абсолютно нужно). Корутины в таком случае могут быть медленее в десятки раз, а значит и нет смысла с ними работать в указанных условиях.
А, ну и сам Update у объекта не стоит забывать. Часто вместо него используют корутины, что так же не правильно и приводит к проблемам. Везде можно использовать либо Task, либо Update.
Давно работаю в Unity с Task и async/await.
Пункты 1-6 работают и при стандартном Task. Пункт 7 спорный. При стандартном Task лог начинается от места старта или ожидания(SyncContext), если последнее произошло. И это отлично, если с UniTask работает лог даже при ожидании - крайне полезно получать лог как при синхронном выполнении. Только по примеру не ясно, так ли это?
Однако, не всё так хорошо и 8 я назову скорее отрицательным и ставящим крест на UniTask для повсеместного использования.
Поначалу я думал, что прошлый опыт использования оказался негативным случайно. Но читая про оптимизацию, понял, что нет. Как часто и бывает, получив некоторое ускорение быстродействия порезали ошибки и НЕЯВНО привели к ситуации с багами.
Задобали тупые картинки с супералгоритмами по типу - вырежу половину функционала и получу буст! (и забывают хотя бы мелким шрифтом прописать условия при которых он будет, но которых может и на пару страниц текстом набраться)Всего то сделал из мультитула заточку. За то вес уменьшился! Да по факту же вырезана основная прелесть async/await!
Суть не в последовательных действиях, с этим и промисы справлялись не плохо, а в применении ожидания одного действия в разных местах. Когда делаешь загрузку ресурсов для игры - плевать на выделение даже мегабайта памяти - её и так выделяется много. А вот сделать менеджер загрузки ресурсов с ожиданием цепочек действий, их агрегацией, да ещё асинхронно по готовности, да буквально за пол часа сделать всё это - очень круто. Сделать загрузку плагинов с зависимостями просто поставив в методы Load ожидание окончание загрузки требуемых плагинов и запустив весь десяток-другой методов загрузки, не заботясь вообще об очерёдности. К примеру IAP, плагины издателя, Ads требуют UnityServ; а плагин издателя ещё и IAP, и FB; а FB нужны ключи сервера и IAP; ну и т.д.).
Про аллокацию так же замечу, что на структуру тоже выделяется память, тоже в неё пишется. Это ни разу не волшебная пуля и минусы в этом тоже есть. Здесь всё аналогично пулу.
Я имел ввиду изменения, которые позволяют увеличить возраст, в котором смогут плодить детей уже обустроенные в жизни люди. Сейчас же при увеличении возраста падает здоровье в целом, либидо, фертильность в целом, а так же частота успешных зачатия, вынашивания, родов(с учётом попыток и успехов). Все эти факторы фактически являются возрастными и их "решение" вполне может влиять на продолжительность жизни.
Женщина которая доживает до 18 лет и с генетически обусловленным желанием иметь как можно больше детей вполне может вносить больше вклада в распространение собственных генов, чем женщина которая дожила до 120 лет и была способна забеременеть вплоть до 60 лет, если они живут в современном цивилизованном обществе, где дети, о которых не особо заботились, всё равно выживают и могут иметь собственных детей.Это уже спор у кого больше, т.е. параллельно может существовать несколько успешных стратегий. Но похоже, всё работает иначе. Падает рождаемость везде. Но, пока, что не везде это приняло такой же большой масштаб. Никто не считает сколько таких женщин умерло в следствие плохой медпомощи, невозможности прокормить детей?
дети, о которых не особо заботились, всё равно выживают и могут иметь собственных детей- никто не проверял, правда ли это возможно с сохранением фертильности. Как минимум, нужны ресурсы на вынашивание, последующее лечение и повтор. Сколько не переживут, либо потеряют фертильность в процессе такой тактики? Государство на деле вот ни черта не торопится брать на себя ответственность, а наоборот - всеми силами скидывает на родителей, как в РФ, так и во всех других странах. Бесплатные школы - это ни разу не достаточны. Они могут только компенсировать новые затраты. А уголовное преследование за оставление в опасности/халатность по отношению к детям очень сильно добавляют хлопот в городской жизни. Новоиспечённую мать скорее посадят, чем помогут ей.https://habr.com/ru/articles/762634/comments/#comment_25995508
Там было исследование по США.
Сам узнал о статье на хабре ~2-6 лет назад. Не найду.
Там учитывали фактор благосостояния, хотя могу ошибаться. Рост продолжительности, на сколько помню был не большой, но статистически значимый.
Если прям супер-полезная мутация, то достаточно несколько поколений. 4 группа крови вон 1 тысячу лет как) А с 1 до 2 основная часть сменилась за 5к лет в европейском.
В масштабах десятков тысяч лет заметны уже большие изменения. Но это возможно всего ~1% от всех изменений, т.к. большую часть изменений мы сейчас можем узнать только статистически по останкам и внешним предположениям . Какова частота закрепляющихся изменений на уровне генов, на сколько знаю, так и не вычислили. У некоторых бактерий это дни или всего ~10 поколений, а порой и того меньше.
Помимо поколений, есть ещё и фактор изменчивости. Сейчас и людей на много больше, и изменчивость на много выше. Потому как ранее закрытые критическими генами пути эволюции сейчас стали открыты в силу развития медицины и изменения формы существования.
Этот вариант больше похож на проигрыш некоторых стратегий. Т.е. как такового увеличения он не даёт - только отрезает всяких чайлдфри, тем самым увеличивая долю иных стратегий.
Есть и другой вариант - увеличение продолжительности жизни вместе с увеличением эффективного возраста фертильности. И, что интересно, по некоторым исследованиям, у поздних детей продолжительность жизни немного выше.
С чего вы взяли, это десятки тысяч лет? Эволюция и сейчас идёт. Только все параметры мы не можем объективно оценить. Впрочем, даже довольно заметные отличия, вроде отсутствующей мышцы/связки не всегда замечаются.
И это при том, что влияние на выживаемость оказывается огромное. Сейчас горизонт возможностей для эволюции как никогда огромен и всё больше расширяется, что сильно ускоряет эволюцию.
Как-то делал домики для детский игры, вся цветовая схема вышла на 128 байт + сам домик на 128 байт(по сути векторная графика, в упрощённом виде/формате). И домики те были на много сложнее менюшек. Так, к примеру, можно менюшку виндового окна сделать, причем, с прозрачностью, неровными краями. Немного сложнее и раза в 1.5 больше по весу будет оптимизированный 9-slice. А это позволит выводить картинку менюшек как в играх(правда, выглядеть будет хуже, как с низкокачественной графикой).
Самое тяжёлое будет со шрифтами - они много весят даже в жёстком монохроме. А программные шрифты тянут программу, что тоже занимает не мало места. Так выйдет, что весить каждый символ наверняка будет даже больше домика.