Apakah Persatuan Lambat? Perhatian LINQ

Sering dikatakan bahwa Persatuan itu lambat. Tetapi berapa banyak? Saya sedang mengembangkan aplikasi Pixel Studio, ini adalah editor seni pixel. Baginya, saya menulis implementasi format GIF saya. Operasi yang paling memakan waktu adalah pengkodean GIF, yaitu algoritma kompresi LZW. Mari kita lihat bagaimana Unity menangani ini.

gambar

Pertama, saya akan segera menjelaskan mengapa saya harus menulis perpustakaan saya sendiri. Ya, semuanya sederhana, perpustakaan System.Windows.Media.Imaging, yang berisi GifBitmapEncoder yang luar biasa, tidak dapat dihubungkan ke Unity. Karena itu saya membaca artikel di hub tentang GIF, mengambil spesifikasi dan membuat GIF saya dengan blackjack.

Tentu saja, saya mulai menulis dan men-debug perpustakaan di Visual Studio, dalam aplikasi konsol. Saya akan menghilangkan momen ini, membosankan dan lama untuk debug, butuh 3 hari. Dalam algoritma seperti itu, saya tidak memiliki pengalaman, biasanya melakukan permainan. Oke, perpustakaan sudah siap. Misalnya, tes "berat" GIF dalam 200 bingkai dan resolusi 256x256 dikodekan dalam 15 detik (Ryzen 7, tentu saja, pada perangkat keras saya). Banyak, pikirku, dan dengan tangan pria itu aku membuat proses kompresi sejajar (seperti Unity harus mendukung utas). Tes GIF dikodekan dalam 5 detik. Hebat!

Cukup salin semua kode sumber ke Unity untuk memeriksa apakah itu berfungsi. Uji pengodean GIF membutuhkan waktu 120 detik. Dalam mode multi-utas (ya, utas dalam Unity berfungsi, yang terpenting adalah tidak menyentuh UI) menyandi gif membutuhkan waktu 180 detik. Facepalm.

Google - masalahnya, ternyata, adalah hal biasa. Menurut laporan serupa, kode algoritmik di Unity berjalan 10-20 kali lebih lambat. Ini diduga terkait dengan implementasi pengumpulan sampah lainnya dan Editor Overhead yang berkabut. Dalam majelis (Windows, Android) situasinya serupa. Dalam rakitan .exe, misalnya, ia bekerja sedikit lebih cepat, sebesar 20%.

Pertanyaan kepada pembaca - apakah saya melakukan sesuatu yang salah, atau apakah ada masalah?

Tautan ke implementasi GIF, yang tertarik: GitHub . Perpustakaan ditulis di bawah C # versi 6 dan. NET 3.5 agar kompatibel dengan versi Unity yang lebih lama. Proyek ini dapat dialihkan ke .NET 4.0, lalu ThreadPool akan bekerja lebih cepat.

UPD: Terima kasih atas komentarnya! Semuanya ternyata agak membingungkan: kedua utas dengan kunci, dan implementasi kurva. Jadi saya menyiapkan kasus sederhana - operasi menjalankan melalui array di LINQ. Yaitu, operasi seperti itu dilakukan selama kompresi LZW (hanya ada pemeriksaan kunci dalam kamus).

gambar

Kami mengeksekusi di aplikasi konsol - 5 ms.
Berjalan di Unity - 2100 ms.

UPD: Bagian dari masalah ditemukan di LINQ. Misalnya, memanggil Contains beberapa kali lebih lambat daripada Array.IndexOf. LINQ hebat, menghemat waktu dan membuat kode lebih indah. Tetapi tidak dalam tugas-tugas terapan seperti bekerja dengan array objek besar. Ini berlaku untuk implementasi LINQ tertentu di Unity.

UPD: Mengoptimalkan algoritma kompresi LZW, menghapus kunci string dalam kamus. LINQ dihapus untuk koleksi besar jika memungkinkan. Saya tidak menyentuh implementasi multithreading. Dan semuanya terbang, bahkan di Android. Tentu saja, perbedaan antara kecepatan aplikasi konsol tetap, tetapi tidak begitu signifikan.

Terima kasih khusus kepada WNeZRoS untuk bantuannya dalam mengoptimalkan kode dan untuk semua peserta dalam diskusi! Meskipun penyebab rem di LINQ tetap belum terpecahkan.

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


All Articles