Unity की Mono समस्या: आपका C# कोड उम्मीद से धीमा क्यों चलता है
(marekfiser.com)- Unity द्वारा इस्तेमाल किया जाने वाला Mono runtime नवीनतम .NET की तुलना में काफ़ी धीमी execution speed दिखाता है, और एक ही C# कोड में अधिकतम 15 गुना तक का अंतर देखा गया है
- वास्तविक game code में Mono-आधारित Unity execution 100 सेकंड और उसी कोड की .NET execution 38 सेकंड मापी गई, जिससे debugging और testing efficiency पर बड़ा असर पड़ता है
- Release mode में भी Mono 30 सेकंड और .NET 12 सेकंड पर रहा, यानी optimized environment में भी 2.5 गुना से अधिक performance gap बना रहता है
- इसकी वजह Mono का अप्रभावी JIT compilation और inlining failure, ज़रूरत से ज़्यादा memory copy आदि हैं, जो .NET की आधुनिक CoreCLR JIT optimization से स्पष्ट रूप से पीछे हैं
- अगर Unity CoreCLR-आधारित .NET modernization पूरा कर लेता है, तो game और editor दोनों में बड़ा performance improvement संभव है, और इससे सभी Unity projects पर लगने वाला छिपा performance tax हट सकता है
Unity में Mono इस्तेमाल होने की पृष्ठभूमि
- Unity 2006 से C# कोड चलाने के लिए Mono framework का इस्तेमाल कर रहा है
- उस समय Mono ही एकमात्र multi-platform .NET implementation था, और open source होने के कारण Unity उसमें बदलाव कर सकता था
- 2014 के बाद Microsoft ने .NET Core को open source किया, और 2016 में .NET Core 1.0 जारी किया
- इसके बाद Roslyn compiler, नया JIT, performance improvements आदि के साथ .NET ecosystem तेज़ी से आगे बढ़ा
- 2018 में Unity engineers ने बताया था कि वे CoreCLR porting पर काम कर रहे हैं, और Mono की तुलना में 2 से 10 गुना performance improvement की उम्मीद है
- लेकिन 2025 के अंत तक भी CoreCLR-आधारित game execution संभव नहीं है
Mono और .NET के बीच performance gap
- Unity project के simulation code को Unity के बाहर .NET पर चलाकर सीधी तुलना की गई
- Unity/Mono environment: 100 सेकंड, .NET environment: 38 सेकंड (Debug mode के आधार पर)
- Release mode में Mono 30 सेकंड और .NET 12 सेकंड रहा, यानी अंतर बरकरार है
- .NET, 4K×4K map को 3 सेकंड के भीतर generate कर देता है, जो इसकी multithread optimization क्षमता दिखाता है
- Mono का अप्रभावी code generation एक बड़ी वजह है, और साधारण loop में भी 15 गुना speed difference देखा गया
Assembly तुलना: Mono vs .NET
- एक ही test code से बने x64 assembly की तुलना में पाया गया कि
- .NET JIT loop invariants को loop के बाहर ले जाता है (hoisting) और केवल न्यूनतम register operations करता है
- Mono दर्जनों
movinstructions के साथ memory copy दोहराता है, और अप्रभावी inlining के कारण performance गिरती है
int.MaxValuerepeat loop execution time- .NET: 750ms, Mono: 11,500ms, Unity Editor(Debug): 67,000ms
- Mono loop के भीतर अनावश्यक memory move और comparison operations बार-बार चलाता है
CoreCLR अपनाने का महत्व
- CoreCLR आधुनिक JIT, Span<T> API, SIMD optimization, hardware instruction support जैसी modern capabilities देता है
- इनसे अतिरिक्त 2 गुना या उससे अधिक performance improvement की संभावना है
- Unity का Burst compiler LLVM-आधारित native code बनाता है, लेकिन इसमें C# feature limitations हैं
- CoreCLR का modern JIT, Burst जैसी performance दे सकता है और इसमें language restrictions कम हैं
- CoreCLR, AOT (ahead-of-time compilation) support भी देता है, जिससे startup speed improvement और JIT-सीमित platforms (जैसे iOS) के लिए समर्थन संभव है
- फिर भी Unity ने अभी IL2CPP बनाए रखने की नीति बताई है
निष्कर्ष: Unity को .NET modernization की ज़रूरत
- Mono, आधुनिक .NET की तुलना में 1.5 से 3 गुना या उससे अधिक धीमी execution performance दिखाता है, और यह सभी Unity projects पर एक छिपी हुई लागत की तरह असर डालता है
- CoreCLR आने पर संभावित लाभ
- runtime performance improvement, तेज़ iterative builds, GC improvement, domain reload हटना, managed code usage बढ़ना
- Unity 6.x roadmap में .NET Modernization शामिल है, लेकिन यह 2026 के बाद के लिए निर्धारित है
- CoreCLR support पूरा होने पर Unity developers और players दोनों को वास्तविक performance transformation मिल सकता है
- फिलहाल Mono की सीमाएँ पूरे Unity ecosystem की performance bottleneck बनी हुई हैं
13 टिप्पणियां
Unity से जुड़ा लेख देखकर बहुत खुशी हुई।
अच्छी तरह पढ़ा।
अगर इसे सफलतापूर्वक अपनाया गया, तो लगता है कि बहुत-से indie game optimization शायद बेहतर हो जाएंगे...
मुझे लगता है कि Mono को ज़रूर CoreCLR में आधुनिक बनाया जाना चाहिए, इसका एक और कारण यह है कि Unity के पास Mono की performance सुधारने में निवेश करने की न तो पर्याप्त स्थिति है और न ही खास इच्छा। मेरा मानना है कि .NET Framework दौर की विरासत को जितनी जल्दी हो सके समेट देना सही होगा. :-D
और मुझे लगता है कि .NET 10 के संदर्भ में यह बात भी ध्यान में रखी जानी चाहिए कि जिन समस्याओं को वे पहले IL2CPP के ज़रिए हल करना चाहते थे, वे अब अलग दिशा में सही तरह से addressed हो रही हैं (Native AOT)।
बेशक, इसकी सीमा यह है कि बीच में edit किए जा सकने वाला C++ code तैयार नहीं होता, लेकिन नतीजे के तौर पर Just-In-Time के बिना native binary production, .NET 8 से शुरू होकर .NET 10 तक आते-आते और अधिक परिपक्व हो गया है.
इसी वजह से, CoreCLR के साथ modernization को लगातार टालते रहना Unity के लिए अच्छा विकल्प नहीं होगा, ऐसा मुझे लगता है. या फिर पूरी तरह किसी अलग भाषा या आधार पर switch करना भी शायद अधिक प्रभावी replacement हो सकता है!
इस बात से भी मैं पूरी तरह सहमत हूँ...
Hacker News टिप्पणियाँ
लेख में कुछ हिस्से ऐसे लगे जैसे उन्हें किसी ऐसे व्यक्ति ने लिखा हो जिसे Unity डेवलपमेंट का कम अनुभव हो
संक्षेप में, Unity डेवलपर्स इस अपडेट को performance boost से ज़्यादा modern language features तक पहुंच के लिए लेकर उत्साहित हैं. और runtime के दौरान GC को न्यूनतम रखना या unmanaged memory और DOTS के जरिए उससे बचना आम बात है
IL2CPP बस .NET IL को C++ में बदलने वाला एक कमज़ोर code generator है, जो optimization compiler पर निर्भर करता है
यह बात Unity ब्लॉग की IL2CPP internals पोस्ट से देखी जा सकती है
Burst/HPC# भी ECS या SoA जैसे ट्रेंड्स का पीछा करते हैं, लेकिन performance अच्छी तरह लिखे गए C++ या CoreCLR C# से कम रहती है
ऊपर से ये तकनीकें closed और Unity-specific हैं, इसलिए बाहर इस्तेमाल नहीं की जा सकतीं. Unity हमेशा धीमे Mono के मुकाबले benchmark दिखाकर marketing करता है
आखिरकार Unity को भी CoreCLR अपनाना पड़ेगा, और तब उसे समझ आएगा कि उसकी मौजूदा जटिल codebase से साधारण C# code ज़्यादा तेज़ हो सकता है
हम IL2CPP का इस्तेमाल नहीं करते क्योंकि वह runtime DLL loading, reflection, FieldOffset struct packing जैसी चीज़ों के साथ compatible नहीं है
modders IL injection के जरिए functionality बढ़ा सकते हैं, जिससे कुल मिलाकर development speed तेज़ हो जाती है
Burst और HPC# हमें उनकी जटिलता और सीमाओं के कारण पसंद नहीं हैं. Mono और .NET के performance gap की वजह से यह और भी निराशाजनक है
editor profiling भी उपयोगी रही, क्योंकि उसने real build के समान अनुपात में performance improvement दिखाया. हालांकि Unity का default profiler सटीक नहीं था, इसलिए हमने खुद का tracing system इस्तेमाल किया
GC अब भी समस्या है. string handling और UI हर frame में garbage बनाते हैं. CoreCLR पर जाने से बेहतर APIs और moving GC के कारण memory fragmentation की समस्या कम हो सकती है
Asset Store शानदार है, लेकिन engine खुद अभी भी अधपका सा लगता है.
Mono-based scripting को CoreCLR में ले जाना संरचनात्मक रूप से जटिल है
अगर Unity सच में अपने core को सुधारना चाहता है, तो उसे Blender 3.x की तरह पूरे editor को redesign करना होगा
अभी यह 1999 के UI जैसा महसूस होता है
अनगिनत plugins और tools “0.x-preview” स्टेज पर अटके रहते हैं, और 5~10 साल बाद या तो चलते नहीं हैं या नई assets के नीचे दब जाते हैं
इसलिए अब मैं सिर्फ 1.0 या उससे ऊपर के version ही इस्तेमाल करता हूँ. नहीं तो छोड़े गए plugin पर निर्भरता बन जाती है और अंत में फिर से port करना पड़ता है
इससे Unity, डेवलपर और यूज़र—सभी का नुकसान होता है
अंदरूनी तौर पर अपने गेम डेवलपमेंट की असफलताओं के कारण उसमें वास्तविक गेम बनाने की समझ की कमी दिखती है
वह सिर्फ मांगे गए features जोड़ती है, लेकिन एकसमान vision नहीं है
अगर performance ज़रूरी है तो Vulkan को सीधे call करना बेहतर है, और अगर portability ज़रूरी है तो WebGPU इस्तेमाल करना चाहिए
अलग-अलग browsers में implementation अलग होने से overhead आता है, लेकिन अगर OS driver स्तर पर WebGPU मिले तो यह समस्या हल हो सकती है
जबकि Godot सरल और सार्थक building blocks देता है, जिनसे आप अपनी पसंद की चीज़ें स्वतंत्र रूप से बना सकते हैं
Asset Store में भी version compatibility की समस्याओं के कारण maintenance मुश्किल हो जाती है, और ज़्यादातर चीज़ें छोड़ी हुई assets बनकर रह जाती हैं
Unity जब किसी उपयोगी asset को खरीदता है, तो उसे ठीक से integrate भी नहीं करता, और competing assets गायब हो जाते हैं
जबकि Unreal Engine ऐसी सुविधाएँ engine-built-in स्तर पर देता है
Unity की IL2CPP में बेहतर GC लाने की भी कोई योजना नहीं दिखती
CoreCLR-based editor आने पर शायद editor build से भी तेज़ हो सकता है
संबंधित चर्चा: Unity CoreCLR और .NET modernization
अगर incremental GC ठीक से काम करे, तो stutter की समस्या भी बहुत बड़ी नहीं रहती
C# खुद बहुत तेज़ हो चुका है, इसलिए Unity को इस transition पर अपनी पूरी क्षमता केंद्रित करनी चाहिए
हमारी टीम को .NET Framework 4.7.2 से .NET 6 पर जाने में कुछ महीने लगे, और उसके बाद LTS upgrades कुछ घंटों का काम रह गए
लगातार देरी हो रही है, और leaders जा रहे हैं
विकल्प के तौर पर .NET 10 आधारित Stride engine की सिफारिश है. इसमें Unity जैसी boundary overhead नहीं है
Godot open source है, लेकिन उसका C# support अस्थिर है, और अगर Web build काम न करे तो वह game jam के लिए उपयुक्त नहीं है
GPU support के साथ एक वास्तविक sandbox solution की ज़रूरत है
priorities लगातार बदलती रहती हैं, requirements संशोधित होती रहती हैं, और काम बार-बार दोहराना पड़ता है
डेवलपर्स अब भी प्रतिभाशाली हैं, लेकिन सतत execution की कमी है
ऐसे बड़े rewrite, CEO के नज़रिए से भी उच्च जोखिम वाला फैसला होते हैं
नतीजतन performance काफ़ी बेहतर हुई, और engine dependency कम होने से code maintenance भी आसान हो गया
Unity concepts को सिर्फ वहीं expose करके जहाँ ज़रूरी था, और tests के जरिए boundaries enforce करके मैंने logical separation की value को गहराई से महसूस किया
अगर root access हो, और उसे WireGuard या Tailscale जैसे network tools के साथ जोड़ा जाए, तो वह portable server के रूप में भी शानदार होगा
.NET 10 के नए GC से गेम stutter भी लगभग खत्म हो जाएगा
अभी मैं अपने मुख्य PC से Sunlight + Moonlight के जरिए गेम stream करके फोन पर खेलता हूँ
high-refresh-rate OLED स्क्रीन की वजह से battery usage भी कम रहता है
यह .NET SDK नहीं है, लेकिन Mono runtime app में bundled रहता है, इसलिए अनुभव लगभग वैसा ही लगता है
Mono के cross-platform फायदे अब लगभग खत्म हो चुके हैं, फिर भी IL2CPP जैसी जटिल hack को बनाए रखना अजीब है
वर्षों से non-standard modifications जुड़ती गई हैं, और किसी बहुत बड़ी कंपनी के बिना उसे फिर से optimize करना भी कठिन है
मुझे लगता है कि इस स्तर के प्रोजेक्ट के लिए 1~2 साल काफ़ी होने चाहिए थे
आह... लगता है Mono अभी भी legacy .NET framework पर आधारित है...
यह गेम नहीं है, लेकिन मैं लगभग 1 लाख लाइनों वाले .NET4.8 + LINQ to SQL + WinForm financial app को .NET10 + Entity Framework पर migrate कर रहा हूँ, और यह स्पष्ट रूप से कहीं ज़्यादा तेज़ महसूस होता है। जो calculation task पहले 10 सेकंड लेता था, वह घटकर 3 सेकंड तक आ गया है!
अगर NuGet compatibility भी जोड़ दें तो अच्छा होगा (या शायद मुझे Unity की ज़्यादा समझ नहीं है?)
आधिकारिक सपोर्ट तो नहीं है... लेकिन NuGetForUnity नाम का एक open source विकल्प मौजूद है।
सिद्धांत रूप में देखें तो .NET Standard 2.0 को target करने वाले Nuget packages को Unity environment में भी import करके इस्तेमाल किया जा सकता है.. लेकिन लगता है कि व्यावहारिक असुविधाएँ काफ़ी हैं.
https://learn.microsoft.com/ko-kr/dotnet/…
बात तो सही है, लेकिन खास तौर पर editor performance की तुलना करने की वजह समझ नहीं आ रही... कम से कम debug build के साथ ही तुलना करके लाते? या नहीं, फिर शायद उसकी विश्वसनीयता और गिर जाती? दूसरी तरफ देखें तो IL2CPP हो या Mono, दोनों ही किसी न किसी तरह से पुराने पड़ चुके तकनीक लगते हैं।
बड़े प्रोजेक्ट्स में editor performance डेवलपमेंट अनुभव को काफ़ी कमज़ोर कर देती है, इसलिए editor performance भी मायने रखती है. Editor खुलने में धीमा है, asset import भी धीमा है, और debugging/testing loop भी धीमा है...
आह... हाँ, बेशक यह भी महत्वपूर्ण है। जब मैंने इसे पहली बार पढ़ा था, तो मुझे लगा कि लेख का लेखक शायद कोड execution speed के कुछ अधिक मूलभूत पहलू पर बात करना चाहता था। जैसा आपने कहा, यह भी सच है कि Unity का editor धीमा है, import भी धीमा है, और कुल मिलाकर test loop भी धीमा है...