Ist die Einheit langsam? Achtung LINQ

Es wird oft gesagt, dass die Einheit langsam ist. Aber wie viel? Ich entwickle eine Pixel Studio-Anwendung, dies ist ein Pixel Art Editor. Für ihn habe ich meine Implementierung des GIF-Formats geschrieben. Die zeitaufwändigste Operation ist die GIF-Codierung, nämlich der LZW-Komprimierungsalgorithmus. Mal sehen, wie Unity damit umgeht.

Bild

Zunächst werde ich sofort klarstellen, warum ich meine eigene Bibliothek schreiben musste. Ja, alles ist einfach. Die System.Windows.Media.Imaging-Bibliothek, die den wunderbaren GifBitmapEncoder enthält, kann nicht mit Unity verbunden werden. Deshalb habe ich im Hub Artikel über GIF gelesen, die Spezifikation übernommen und mein GIF mit Blackjack erstellt.

Natürlich habe ich angefangen, die Bibliothek in Visual Studio in einer Konsolenanwendung zu schreiben und zu debuggen. Ich werde diesen Moment weglassen, es war langweilig und lange zu debuggen, es dauerte 3 Tage. In solchen Algorithmen hatte ich keine Erfahrung und machte normalerweise Spiele. Okay, die Bibliothek ist fertig. Zum Beispiel wird ein Test "schweres" GIF in 200 Frames und einer Auflösung von 256x256 in 15 Sekunden codiert (Ryzen 7 natürlich auf meiner Hardware). Viel, dachte ich, und mit der Hand des Gentlemans habe ich den Komprimierungsprozess parallel gemacht (so wie Unity Threads unterstützen sollte). Das Test-GIF wurde in 5 Sekunden codiert. Großartig!

Kopieren Sie einfach den gesamten Quellcode in Unity, um zu überprüfen, ob er funktioniert. Das Testen der GIF-Codierung dauert 120 Sekunden. Im Multithread-Modus (ja, Threads in Unity funktionieren, die Hauptsache ist, die Benutzeroberfläche nicht zu berühren) dauert das Codieren eines Gifs 180 Sekunden. Gesichtspalme.

Google - das Problem ist, wie sich herausstellt, weit verbreitet. Ähnlichen Berichten zufolge läuft der algorithmische Code in Unity 10 bis 20 Mal langsamer. Dies hängt angeblich mit einer anderen Implementierung der Speicherbereinigung und dem nebligen Editor-Overhead zusammen. In Baugruppen (Windows, Android) ist die Situation ähnlich. In der .exe-Assembly arbeitet es beispielsweise etwas schneller, um 20%.

Frage an die Leser - mache ich etwas falsch oder gibt es ein Problem?

Link zur Implementierung von GIF, die interessiert sind: GitHub . Die Bibliothek wurde unter C # Version 6 und .NET 3.5 geschrieben, um mit älteren Versionen von Unity kompatibel zu sein. Das Projekt kann auf .NET 4.0 umgestellt werden, dann arbeitet ThreadPool viel schneller.

UPD: Danke für die Kommentare! Alles fiel etwas verwirrend aus: beide Threads mit Sperren und eine Kurvenimplementierung. Also habe ich einen einfachen Fall vorbereitet - den Vorgang des Durchlaufens eines Arrays in LINQ. Eine solche Operation wird nämlich während der LZW-Komprimierung ausgeführt (nur gibt es eine Schlüsselprüfung im Wörterbuch).

Bild

Wir führen in der Konsolenanwendung aus - 5 ms.
Laufen in Unity - 2100 ms.

UPD: Ein Teil des Problems ist in LINQ zu finden. Beispielsweise ist das Aufrufen von Contains um ein Vielfaches langsamer als Array.IndexOf. LINQ ist großartig, spart Zeit und macht den Code schöner. Aber nicht bei angewandten Aufgaben wie dem Arbeiten mit großen Arrays von Objekten. Dies gilt für eine bestimmte LINQ-Implementierung in Unity.

UPD: Der LZW-Komprimierungsalgorithmus wurde optimiert und Zeichenfolgenschlüssel im Wörterbuch entfernt. LINQ für große Sammlungen wurde nach Möglichkeit entfernt. Ich habe die Implementierung von Multithreading nicht angesprochen. Und alles flog, auch auf Android. Natürlich bleibt der Unterschied zwischen der Geschwindigkeit der Konsolenanwendung bestehen, aber er ist nicht so bedeutend.

Besonderer Dank geht an WNeZRoS für die Hilfe bei der Optimierung des Codes und an alle Diskussionsteilnehmer! Obwohl die Ursache der Bremsen in LINQ ungelöst bleibt.

Source: https://habr.com/ru/post/de415923/


All Articles