Пока в экспериментальном режиме. Будет переписана в будущем с учетом Лодов, информации о которых в формате контейнера пока нет, а так-же пока сам ассет не знает в каком состоянии геом. данные.
Т.к. зависимости добавляются через кастомные CMakeLists, то пришлось писать эти правила самостоятельно (но по большей части копипаст из оригинала)
ThreadManager и AsyncTask
Теперь собственно об этих классах. Ранее я писал о том, что скорее всего придется реализовать шаблон пула потоков, но чуть подумав пришел к выводу, что более гибким решением будет использование его более простой реализации - Очередь потоков.
Как это работает. ThreadManager при старте запрашивает систему о том, сколько параллельных задач может выполнить система (это можно переопределить через параметр max_concurrent_tasks в Engine.ini с возможностью перевыставить этот параметр в "пользовательском" конфиге), с ограничением, что если этот параметр больше полученного от системы значения, то движок уйдет в исключение (думаю понятно, зачем это сделано). Так-же в этом классе хранится очередь задач AsyncTask и производных от них.
Каждый AsyncTask является отдельным потоком. Его нельзя запустить произвольно - только поставить в очередь на исполнение. ThreadManager в каждом тике основного потока опрашивает очередь и смотрит в каком состоянии находится задача. Если состояние Pending и если текущее кол-во запущенных задач меньше, чем max_concurrent_tasks, то запускает ее. Если задача закончила выполнение, то убирает ее из очереди и запускает следующую. Если очередь пуста, то Тик для ThreadManager отключается, тем самым дополнительно экономя ресурсы основного потока.
Таким образом, мы всегда можем быть уверены, что при использовании этого механизма у нас будет задействовано оптимальное для конкретной системы кол-во потоков. Исключение в этом случае есть - это пресловутые E-ядра (или малые ядра, если хотите). Пока не знаю, что с ними делать, т.к. неначем тестировать. Сложность в том, что при запуске задачи мы не можем быть уверены, на каком ядре система запустит эту задачу (на большом или малом). Иными словами, если задача, которая рассчитана на запуск на полноценном ядре запустится на малом, то будет просадка производительности, с которой мы ничего не сможем сделать.
Так-же пока не придуман механизм "синхронизации" потоков и механизм блокировки данных, чтобы избежать случайного обращения к ним, пока они гоняются в потоке. Это в процессе.