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

Действительно ли Unity медленный? Осторожно, LINQ

Время на прочтение2 мин
Количество просмотров13K
Часто говорят, что Unity медленный. Но насколько? Я разрабатываю приложение Pixel Studio, это редактор пиксель-арта. Для него я написал свою реализацию формата GIF. Самая трудоемкая операция — кодирование GIF, а именно алгоритм сжатия LZW. Посмотрим, как с этим справится Unity.

image

Во-первых, сразу уточню, почему пришлось писать свою библиотеку. Да все просто, библиотеку System.Windows.Media.Imaging, в которой находится замечательный GifBitmapEncoder, нельзя подключить к Unity. Поэтому почитал статьи на хабре про GIF, взял спецификацию и сделал свой GIF с блэкджеком.

Писать библиотеку и отлаживать ее, я разумеется, начал в Visual Studio, в консольном приложении. Опущу этот момент, отлаживать было скучно и долго, заняло 3 дня. В таких алгоритмах опыта у меня не было, обычно занимаюсь играми. Ладно, «библиотэка» готова. Например, тестовая «тяжелая» гифка в 200 кадров и разрешении 256х256 кодируется за 15 секунд (на моем железе, разумеется, Ryzen 7). Много, подумал я, и с барской руки сделал процесс сжатия параллельным (вроде, Unity должен поддерживать потоки). Тестовая гифка стала кодироваться за 5 секунд. Отлично!

Просто копирую все исходные коды в Unity, чтобы проверить работоспособность. Кодирование тестовой гифки занимается 120 секунд. В многопоточном режиме (да, потоки в Unity работают, главное UI не трогать) кодирование гифки занимает 180 секунд. Facepalm.

Гуглю — проблема, оказывается, распространенная. По похожим сообщениям, алгоритмический код в Unity выполняется в 10-20 раз медленнее. Связано это, якобы, с другой реализацией сбора мусора и туманным Editor Overhead. В сборках (Windows, Android) ситуация аналогичная. В .exe сборке, например, работает незначительно быстрее, процентов на 20%.

Вопрос к читателям — это я что-то делаю неправильно, или проблема имеет место быть?

Ссылка на реализацию GIF, кому интересно: GitHub. Библиотека писалась под C# версии 6 и .NET 3.5, чтобы иметь совместимость со старыми версиями Unity. Проект можно переключить в .NET 4.0, ThreadPool тогда будет работать намного быстрее.

UPD: Спасибо за комментарии! Получилось все немного запутанно: и потоки с блокировками, и кривая реализация. Вот я подготовил простой кейс — операция пробегания по массиву в LINQ. А именно такая операция выполняется при сжатии LZW (только там проверка ключей в словаре).

image

Выполняем в консольном приложении — 5 ms.
Выполняем в Unity — 2100 ms.

UPD: Частично проблема найдена в LINQ. Например, вызов Contains в несколько раз медленнее, чем Array.IndexOf. LINQ это здорово, она позволяет сэкономить время и сделать код красивее. Но не в таких прикладных задачах, как работа с большими массивами объектов. Это касается конкретной реализации LINQ в Unity.

UPD: Оптимизировал алгоритм сжатия LZW, убрал строковые ключи в словаре. Убрал LINQ для больших коллекций, где это было возможно. Реализацию многопоточности не трогал. И все залетало, даже на Android. Конечно, разница между скоростью работы консольного приложения осталась, но она уже не такая значительная.

Отдельное спасибо WNeZRoS за помощь в оптимизации кода и всем участникам обсуждения! Хотя причина тормозов в LINQ остается нераскрытой.
Теги:
Хабы:
+8
Комментарии67

Публикации

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

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн