2 पॉइंट द्वारा GN⁺ 2024-10-20 | 1 टिप्पणियां | WhatsApp पर शेयर करें

-.NET 9.0 कई सामान्य LINQ scenarios में .NET 8 की तुलना में execution time को काफी कम करता है, और कुछ benchmarks में allocation भी हटा देता है

  • array या List<T> को iterate करते समय TryGetSpan() से ReadOnlySpan<T> प्राप्त कर iteration cost घटाना प्रमुख सुधारों में से एक है
  • TryGetSpan() type comparison से TSource[] और List<TSource> की पहचान करता है, लेकिन List<T> की internal array को span के रूप में लेना capacity बदलने पर invalidate हो सकने वाला Unsafe-श्रेणी का optimization है -.NET 9 का LINQ सामान्य call chains को पहचानकर specialized iterator बनाता है, और Count(), First(), Last(), ElementAt(), Sum() जैसे terminal methods में अतिरिक्त optimization लागू करता है
  • सिर्फ migration और recompilation से भी कुछ LINQ performance improvements मिल सकते हैं, और इसमें SIMD उपयोग तथा empty sequence की early detection जैसे optimizations भी शामिल हैं

arrays और lists पर iteration तेज़ क्यों हुआ

  • पहला benchmark Enumerable.Range(1, 10_000).ToArray() को IEnumerable<int> के रूप में रखकर Count, All, Any, First, Single, Last चलाता है और .NET 8 व .NET 9 की तुलना करता है
  • BenchmarkDotNet का उपयोग किया गया है, और project को net8.0;net9.0 target करना चाहिए तथा Release mode में compile करना चाहिए
  • .NET 9 में कई methods का execution time काफी घटता है और allocation भी समाप्त हो जाता है
    • LinqCount: 16,198.490 ns से 3,043.563 ns, 32 B allocation से बिना allocation
    • LinqAny: 17,096.735 ns से 2,483.927 ns, 32 B allocation से बिना allocation
    • LinqFirst: 15,289.747 ns से 2,243.341 ns, 32 B allocation से बिना allocation
    • LinqSingle: 21,684.114 ns से 4,884.329 ns, 32 B allocation से बिना allocation
    • LinqAll: 10.588 ns से 2.562 ns, 32 B allocation से बिना allocation
    • LinqLast: 15.967 ns से 6.918 ns

TryGetSpan() क्या फर्क लाता है

  • performance सुधार का मुख्य कारण TryGetSpan() का उपयोग है
  • अगर iterate किया जाने वाला enumerable array या list हो, तो TryGetSpan() ReadOnlySpan<T> लौटाता है जिससे iteration तेज़ हो जाती है
  • core branching code source.GetType() == typeof(TSource[]) या source.GetType() == typeof(List<TSource>) की जांच के बाद span प्राप्त करता है
    • array को Unsafe.As<TSource[]>(source) से संभाला जाता है
    • list के लिए CollectionsMarshal.AsSpan(Unsafe.As<List<TSource>>(source)) से internal array पर span लिया जाता है
  • code में source.GetType() दो बार call होता है और casting के बाद null check से नहीं निपटा जाता, लेकिन .NET performance experts ने C# compiler और JIT optimizations को ध्यान में रखकर यह तरीका चुना है
  • अत्यधिक optimized .NET stack में micro-optimization कई बार सतह पर दिखने वाली बातों से अलग नतीजे दे सकती है

CollectionsMarshal.AsSpan() की सीमाएँ

  • List<TSource> अंदरूनी रूप से एक array को reference करता है, और list की capacity बढ़ने या घटने पर नया array बनाकर उसी को reference करता है
  • CollectionsMarshal.AsSpan(Unsafe.As<List<TSource>>(source)) इस internal array से Span<TSource> प्राप्त करता है
  • अगर list capacity किसी भी तरह बदलती है, तो इस तरीके से मिला array invalidate हो सकता है
  • इस सीमा के कारण yield जैसी deferred iteration वाली कुछ Enumerable operations के लिए इस optimization पर निर्भर रहना कठिन है
  • System.Runtime.CompilerServices.Unsafe नाम ही इस जोखिम की ओर संकेत करता है

TryGetSpan() call का दायरा

  • NDepend से System.Linq.dll को scan करके TryGetSpan() के direct और indirect callers देखे गए
  • analysis के लिए assembly path C:\Program Files\dotnet\shared\Microsoft.NETCore.App\9.0.0-rc.1.24431.7\System.Linq.dll है
  • TryGetSpan() से code query बनाकर callers की पहचान की गई, और 56 matching methods को dependency graph में export किया गया
  • कई standard Enumerable methods collection के array या list होने पर span iteration की कोशिश करते हैं
  • लेकिन list की internal array को पकड़े रखने का तरीका सुरक्षित नहीं है, इसलिए deferred execution वाली operations पर अब भी सीमाएँ हैं

specialized iterator आधारित optimization

  • दूसरा benchmark Consolidate LINQ’s internal IIListProvider/IPartition into base Iterator class PR में दिए गए उदाहरणों का उपयोग करता है
  • test cases में Distinct().First(), Append().Select().Last(), Reverse().Count(), DefaultIfEmpty().Select().ElementAt(), Skip().Take().ElementAt(), Union().First(), Select().Where().Select().Sum() आदि शामिल हैं
  • .NET 9 में कुछ call chains बेहद तेज़ हो जाती हैं
    • DistinctFirst: 65.318 ns से 11.192 ns, 328 B allocation से बिना allocation
    • AppendSelectLast: 4,122.007 ns से 2.661 ns, 144 B allocation से बिना allocation
    • DefaultIfEmptySelectElementAt: 4,090.818 ns से 5.724 ns, 144 B allocation से बिना allocation
    • RangeUnionFirst: 66.309 ns से 6.193 ns, 344 B allocation से बिना allocation
    • ListSkipTakeElementAt: 6.268 ns से 2.916 ns
    • RangeReverseCount: 11.024 ns से 6.134 ns
  • इसके उलट SelectWhereSelectSum .NET 8 के 3,959.622 ns से .NET 9 में 4,460.008 ns तक धीमा हुआ, और 112 B allocation भी बना रहा

सामान्य LINQ chains की पहचान

  • .NET performance team ने code को सामान्य LINQ call chains पहचानने के लिए डिजाइन किया है
  • किसी खास chain का पता चलते ही अधिक कुशल तरीके से workflow संभालने वाला specialized iterator बनाया जाता है
  • जब chain Count(), First(), Last(), ElementAt(), Sum() जैसे methods पर खत्म होती है, तब अतिरिक्त optimization संभव होती है
  • उदाहरण के लिए OrderBy(criteria).First() को Min(criteria) की तरह execute होने के लिए optimize किया जा सकता है

Iterator<T> और derived classes की संरचना

  • LINQ के अंदर abstract base class Iterator<T> और उसकी 40 derived classes हैं
  • ये classes सभी Enumerable class के भीतर nested हैं
  • Iterator<T> एक abstract class है, लेकिन methods virtual हैं, इसलिए derived classes सिर्फ ज़रूरी methods को override करती हैं
  • यही संरचना हर call chain के लिए specialized behavior रखने का आधार बनती है

ListWhereSelectIterator<TSource, TResult> उदाहरण

  • ListWhereSelectIterator<TSource, TResult> list पर Where(...).Select(...) chain को एक ही iterator में संभालता है
  • यह iterator ListWhereIterator<TSource, TResult> के Select() override में बनता है
  • ListWhereIterator<TSource> तब बनता है जब Enumerable.Where() जांचता है कि source List<TSource> है या नहीं
  • ListWhereSelectIterator<TSource, TResult> TryGetFirst() या TryGetLast() जैसे methods को override नहीं करता
  • performance सुधार का मुख्य बिंदु यह है कि list पर बहुत सामान्य Where(...).Select(...) chain को दो iterators की जगह एक iterator में जोड़ दिया गया है
    • MoveNext() के भीतर _predicate और _selector दोनों delegates साथ में call होते हैं

IListSkipTakeIterator<TSource> उदाहरण

  • IListSkipTakeIterator<TSource> लागू हो सकने पर बनाया जाने वाला specialized iterator है
  • MoveNext() _state - 1 को list के 0-based index की तरह उपयोग करता है
  • अलग index field रखना पढ़ने में आसान होता, लेकिन iterator field size घटाने के लिए _state में bias डालकर store किया गया है
  • इस iterator का optimization _minIndexInclusive और _maxIndexInclusive range के बाहर के elements को बेवजह iterate न करने में है

सिर्फ migration से मिलने वाले अतिरिक्त optimizations

  • .NET 9 में कई सामान्य LINQ scenarios और तेज़ हो गए हैं
  • नए .NET version के सुधार पाने के लिए ज़रूरी काम migration और recompilation है
  • LINQ को अन्य तरीकों से भी optimize किया गया है
    • integer sequences के sum जैसे मामलों में जहाँ संभव हो SIMD का उपयोग किया जाता है
    • empty sequences को जल्दी पहचान लेने से enumeration cost कम होती है
  • DeepDotnet videos Scott Hanselman और Stephen Toub के साथ .NET सीखने की सामग्री के रूप में देखे जा सकते हैं

1 टिप्पणियां

 
GN⁺ 2024-10-20
Hacker News की रायें
  • मेरे हिसाब से LINQ का सबसे उपयोगी हिस्सा IQueryable का syntax tree-आधारित extension structure भी नहीं है, और न ही language में built-in syntax, बल्कि IEnumerable extension methods हैं
    पहले इसे कुछ हद तक भ्रमित करने वाले नाम “LINQ to Objects” से बुलाया जाता था, और यह C# को functional style में संक्षेप में लिखने देता है
    मूल लेख मुख्य रूप से इन्हीं extension methods की optimizations पर है
    Haskell सीखने के बाद ही यह तरीका ठीक से समझ आया, और यह lazy evaluation जैसी Haskell की कुछ खूबियां और pitfalls भी साझा करता है
    बिना सोचे-समझे इस्तेमाल करने पर code कठिन और धीमा हो सकता है, इसलिए अगर team में basic functional idioms और lazy evaluation समझने वाला कोई नहीं है, तो मैं इसकी सिफारिश नहीं करूंगा

    • मैं भी IEnumerable और IQueryable पर LINQ extensions के functional पहलू को पसंद करता हूं
      इनके बारे में reason करना आसान होता है, और Entity Framework जैसी जगहों में यह हमेशा सबसे तेज विकल्प नहीं होता, लेकिन आम तौर पर काफी अच्छा विकल्प होता है
      EF के बजाय Dapper इस्तेमाल करना भी मुझे पसंद है
      हालांकि C# projects में abstraction layers बेवजह बहुत ज्यादा हो जाने की प्रवृत्ति होती है, और “enterprise” development आम तौर पर देखने में तकलीफदेह होता है
    • मैं भी LINQ को इसी तरह इस्तेमाल करता हूं
      naming में थोड़ा non-standard हिस्सा है, लेकिन जरूरत की सारी चीजें मौजूद हैं
      Eric Lippert ने LINQ से जोड़कर monads समझाने वाली एक शानदार लेख-श्रृंखला लिखी थी: https://ericlippert.com/2013/04/02/monads-part-twelve/
    • मैंने LINQ में हमेशा सिर्फ method syntax ही इस्तेमाल किया है
      मुझे host language के अंदर एक और “built-in” language आना पसंद नहीं है, और अंतिम परिणाम भी आखिरकार C# में ही लौटना होता है
      Entity Framework या Dapper जैसे ORM इस्तेमाल न करने पर भी, SQL समेत data access logic को अलग abstracted project में रखना बेहतर होता है
      इससे वह पूरे application में नहीं फैलता, और अगर कभी दूसरा RDBMS चाहिए हो तो उसे बदला जा सकता है
      20 साल में असल में ऐसा सिर्फ एक बार हुआ है, लेकिन फिर भी
      junior developers जब LINQ इस्तेमाल करते हैं, तो profiler और debugger जोड़ देने से उन्हें अंदर क्या हो रहा है यह समझने में मदद मिलती है
      कभी-कभी पहले for loop और सामान्य C# logic से लिखवाकर फिर LINQ implementation से तुलना कराना भी उपयोगी होता है, ताकि वे दोनों approaches के फायदे-नुकसान देख सकें
    • अगर आपको Haskell पसंद है, तो LINQ के query syntax का उपयोग करके combinator parser construction जैसे दूसरे use cases भी पसंद आ सकते हैं
      query syntax IEnumerable के लिए hardcoded नहीं है; बस default behavior वैसा है, और इसे लगभग कहीं भी इस्तेमाल किया जा सकता है
      यह operator overloading जैसा थोड़ा काम करता है
      [1]: https://github.com/acple/ParsecSharp/blob/da8d0cb9ec39e28dd9...
    • LINQ syntax कल गायब भी हो जाए तो मुझे खास अफसोस नहीं होगा, लेकिन functional composition सचमुच ताकतवर है और maintain करना भी आसान है
  • समझ नहीं आता कि dotnet team tooling में और ज्यादा resources और time क्यों नहीं लगाती
    doctest और documentation generation, actual code के पास ही बेहतर और तेज unit tests लिखने की capability, source code accessibility, F12 दबाने पर DLL decompile किए बिना काम करने वाला environment, और pkg.go.dev या docs.rs जैसा packages और docs का central hub चाहिए
    ज्यादातर NuGet packages में या तो documentation बिल्कुल नहीं होती, या सिर्फ GitHub README होता है, या छोटी-सी wiki होती है
    Rust, Go, Java, Python जैसे दूसरे ecosystems इस मामले में कई प्रकाश-वर्ष आगे हैं

    • मजाक में कहने का मन करता है कि Microsoft ने OpenAI में इसलिए invest किया, क्योंकि .NET/NuGet package documentation explore करने का वही इकलौता समझदारी भरा तरीका है
      लेकिन डरावनी बात यह है कि यह सच के काफी करीब भी लगता है
    • अब Microsoft documentation में जिस method को आप देख रहे हैं, उसके source पर सीधे जाने वाला link शामिल होता है
      उदाहरण: https://learn.microsoft.com/en-us/dotnet/api/system.string.s...
      NuGet package source के लिए भी Source Link चालू करने पर यह आसानी से संभव है, लेकिन यह अभी relatively नया feature है, इसलिए सभी packages ने इसे लागू नहीं किया है
    • सहमत हूं, लेकिन open source C# का relatively हाल की चीज होना भी एक वजह हो सकती है
      लगता है आज भी ज्यादातर C# code companies में closed source के रूप में ही लिखा जाता है
      अगर Microsoft पिछले कुछ वर्षों की तरह खुलेपन की दिशा में आगे बढ़ता रहा, तो समय के साथ यह बेहतर होगा
      इनमें से कुछ features Resharper जैसे tools देते हैं, और सोचता हूं कि कहीं इनके बीच एक-दूसरे के क्षेत्र में दखल न देने का कोई explicit या implicit agreement तो नहीं है
      सच कहूं तो C# projects में मैंने जो documentation देखी है, वह ज्यादातर खराब quality की थी, इसलिए आखिर में source code ही देखना पड़ता है
      autocomplete tools बहुत होने पर भी पढ़ने में खास मदद नहीं करते, सिर्फ लिखने में मदद करते हैं—मेरा अनुभव यही है
    • Sandcastle Help File Builder बहुत लंबे समय से मौजूद है, और याद पड़ता है कि यह Microsoft के internal project के रूप में शुरू हुआ था, लेकिन अजीब बात है कि इसका इस्तेमाल करने वाली libraries कम हैं
      https://github.com/EWSoftware/SHFB
    • code के पास test लिखने का तरीका भी है: https://clipperhouse.com/go-test-csharp/
      इसे recommend करूं या नहीं, पक्का नहीं
      मैंने खुद आजमाया और फिर वापस हटा दिया; शायद build artifact caching खराब होने की वजह से tests ज्यादा समय लेते लग रहे थे
  • इसे “LINQ performance improvement” कहने के बजाय “अपने List implementation की performance improvement” कहना ज़्यादा सही होगा
    लगता है Microsoft आम सुधारों की बजाय उन हिस्सों को बेहतर बनाने में समय लगाता है जिनकी उन्हें खुद जरूरत होती है
    LINQ, खासकर method extensions नहीं बल्कि query syntax, में निवेश की जरूरत है
    मुख्य रूप से lambda allocations और, अगर संभव हो, compile time पर lambda reduction की जरूरत है
    value-type local lambdas या ऐसी strategy चाहिए जिससे lambda allocations अभी की तरह overhead न बनें
    LINQ variables में भी अब wildcard (_) support होना चाहिए, लेकिन जब lambdas में इसे लाया गया तो इसे पूरी तरह नजरअंदाज कर दिया गया
    साथ ही LINQ expression के आखिरी item के रूप में select ... के बजाय IEnumerable, Option जैसे lifted types इस्तेमाल किए जा सकने चाहिए
    कुछ use cases में select गैर-जरूरी overhead बनाता है, और tail-recursive LINQ expressions जैसी चीजों को भी सीमित करता है
    मेरी library जैसी libraries, जो LINQ पर पूरी तरह निर्भर हैं लेकिन IEnumerable, IQueryable, LINQ extensions इस्तेमाल नहीं करतीं, लगातार नजरअंदाज की जाती हैं
    क्योंकि Microsoft सिर्फ अपने projects की performance improvement पर ध्यान देता है
    इसका अच्छा उदाहरण improved lambda inference है
    इसे इसलिए आगे बढ़ाया गया क्योंकि ASP.NET Core की Minimal API को इसकी जरूरत थी
    लगता है language और framework features का बड़ा हिस्सा community needs से ज्यादा Microsoft की internal needs से चलता है
    सबसे खराब बात यह है कि LINQ extensions Select, SelectMany, Where ही नहीं, बल्कि GetAwaiter जैसे magic methods का set लगातार बढ़ता जा रहा है
    Microsoft इस magic को हटाने के लिए सच में जरूरी higher-kinded traits जोड़ने के बजाय, अपने लिए, मुख्यतः compiler के लिए, features जोड़ रहा है
    इसलिए सब कुछ weakly typed ही रह जाता है, और compiler बस मोटे तौर पर ही चीजें पकड़ पाता है
    LINQ languages के बीच मुख्य differentiators में से एक है, लेकिन C# 3 के बाद से इसे लगभग छोड़ दिया गया है
    अब भी LINQ को list traversal, खासकर अपने list implementation traversal के लिए ही उपयोगी मानना सच में अफसोसजनक है
    performance improvements के लिए आभारी हूं और इससे कई users को मदद मिलेगी, लेकिन focus हमेशा इतना narrow रहता है कि इसकी potential सीमित हो जाती है
    [1] https://github.com/louthy/language-ext/

    • अगर आपके पास उपयोगी feedback है तो dotnet/runtime में issue खोलना या PR भेजना अच्छा होगा
      article में बताई गई LINQ performance improvements में से काफी इसी तरह आई थीं
    • library बहुत interesting लगती है, लेकिन कुछ हद तक इसे पहले से ही ऐसे setup किया गया लगता है कि इसे आसानी से ignore किया जा सके
      इसमें कई using statements हैं, जो उन लोगों के लिए बड़ी समस्या नहीं है जो project को जरूरत के हिसाब से छोटे हिस्सों में बांटना और concerns अलग करना समझते हैं
      लेकिन ज्यादातर developers projects को इस तरह structure नहीं करते, और ऐसी छोटी चीजें average developer के लिए barrier बन सकती हैं
      junior developers अक्सर standard LINQ syntax और methods, खासकर performance में भी पहले से struggle करते हैं
      README में इस बात का जिक्र होना अच्छा है
      आम तौर पर लोग library को “बेचने” में लगे रहते हैं, लेकिन आपने सच में लिखा है कि यह किसमें strong है और इसका purpose क्या है, यह पसंद आया
      non-idiomatic होने का जिक्र भी C#/.NET सीखने वालों के लिए समस्या हो सकता है
      Microsoft शायद चाहता होगा कि tools और language कुछ खास practices follow करें, और functional programming के हिसाब से natural naming, Microsoft के लिए improvements पर विचार करते समय काफी बड़ा hurdle लग सकता है
      मैंने repository को star किया है, और आपने जो बनाया है उसमें मेरी काफी दिलचस्पी है
      हाल में बनाए गए कुछ बड़े applications में मैंने Option से मोटे तौर पर मिलता-जुलता Result type इस्तेमाल किया था
      लेकिन library को फिर से देखकर लगा कि मैं खुद को functional programming काफी जानने वाला समझता था, जबकि असल में ऐसा नहीं है
      C# मुझे काफी अच्छी तरह आता है और मैंने complex काम भी किए हैं, लेकिन functional programming पर बहुत पढ़ने के बावजूद इसे सीखना अब भी मुश्किल है, और F# For Fun And Profit ही अब तक सबसे ज्यादा समझ में आया
      कुल मिलाकर इसका मतलब यह नहीं कि आप कुछ गलत कर रहे हैं
      Microsoft अपने ecosystem के बहुमत, यानी average या beginner developers, को target करेगा
      उम्मीद है इस library को internal improvements का फायदा मिल सके
      साफ दिखता है कि इसमें बहुत समय लगाया गया है, और सिर्फ GitHub stars की संख्या भी यह बताने के लिए काफी है कि लोग इसे सच में इस्तेमाल कर रहे हैं और इससे मदद पा रहे हैं
      अगर मेरी बात dismissive लगी हो तो माफ करें, लेकिन आपका काम interesting है और documentation भी ऐसी लगती है कि अनजान concepts को धीरे-धीरे सीखा जा सके
  • C# जितना ज्यादा F# से उधार ले, उतना बेहतर
    इंतजार है कि discriminated unions आखिरकार C# में आएं ताकि domain modeling ठीक से की जा सके

    • .NET community में ऐसी बातें अक्सर सुनना interesting है
      हर बार सवाल उठता है, “बस F# क्यों नहीं इस्तेमाल करते?”
      C# कई सालों से catch-up खेल रहा है
      अगर .NET ecosystem में कई innovations F# आगे बढ़ा रहा था और features के मामले में कई साल आगे था, तो उस मेहनत को usage से reward क्यों नहीं किया जाता, यह सोचने वाली बात है
      अगर आप language development की कोई direction चाहते हैं तो उसे अपने actual choices से encourage करना चाहिए
      Java ecosystem में यह तरीका काम कर चुका है, और अब Java भी improve हो रहा है
      market बड़ा होने पर engineering effort भी बढ़ता है, ऐसा positive feedback loop बन सकता है
      कई साल forums पढ़ने पर लगता है कि C# camp “बस” अपने ही camp में रहकर इंतजार करना चाहता है
      यह थोड़ा tribalism जैसा दिखता है, जैसे team “C#” हो
      दूसरे language ecosystems में ऐसी culture कम ही दिखी, और impression यह है कि अगर F# .NET के अलावा किसी और ecosystem में होता तो शायद बहुत पहले फल-फूल चुका होता
    • units of measure types भी सच में चाहिए
      engineering या scientific code की maintainability कहीं आसान हो जाएगी
    • OneOf[0] और Dunet[1] का इस्तेमाल करके discriminated unions पहले से ही काफी आसानी से लाई जा सकती हैं
      practical example: https://chrlschn.dev/blog/2024/07/csharp-discriminated-union...
      [0] https://github.com/mcintyre321/OneOf
      [1] https://github.com/domn1995/dunet
    • यह open secret है कि F# C# और VB.NET features के लिए testbed है, और Hanselman जैसे official लोगों ने भी इसे कई बार quote किया है
  • दूसरी भाषाओं या ecosystems में काम करते समय जिस चीज़ की सबसे ज़्यादा कमी महसूस होती है, वह LINQ है
    standard library में ऐसी functionality होना वाकई बहुत अच्छा है, और दी गई constraints के भीतर इसे खूबसूरती से design किया गया है

  • .NET 9 में सभी performance improvements को कवर करने वाले सालाना, किताब जितने लंबे article में इससे जुड़ा section है
    https://devblogs.microsoft.com/dotnet/performance-improvemen...
    अजीब तरह से HN ने इसे फिर से submit करने की अनुमति नहीं दी, इसलिए article front page पर नहीं आ पाया और दब गया

  • LINQ की आदत पड़ जाए, और आम तौर पर उन domains में काम करने लगें जहाँ LINQ चमकता है, तो फिर किसी और तरीके पर लौटने का मन नहीं करता

    • दोस्तों, LINQ के आदी मत बनो
      LINQ तुम्हें जकड़ लेगा, और तुम LINQ के बिना वाले environments से चिढ़ने लगोगे
    • फिर भी यह polars जैसी चीज़ों से कम powerful है
  • सोच रहा हूँ कि dotnet से end-to-end web development सीखने के लिए कोई comprehensive book या tutorial है क्या
    जो चीज़ें मिलीं, उनमें से ज़्यादातर या तो बहुत basic थीं, या पुरानी, या low quality

    • .NET web development में आजकल जो नया और hot है वह Blazor है, लेकिन Microsoft blogosphere के बाहर यह ज़्यादा popular नहीं है और आगे भी शायद नहीं होगा
      निजी तौर पर मुझे लगता है यह Silverlight जैसा रास्ता लेगा
      पुरानी technologies भी .NET 9 में अब भी मौजूद हैं, काम करती हैं और maintain की जा रही हैं
      आजकल .NET से web development करने का मतलब ज़्यादातर HTTP/JSON/REST API बनाना और उसे अपनी पसंद के front-end framework से जोड़ना है
      मेरे मामले में मैं React या NextJS इस्तेमाल करता हूँ
      search terms के लिए ASP.NET WebApi या ज़्यादा modern तौर पर ASP.NET Minimal API अच्छे रहेंगे
      Razor के साथ .NET MVC server-side rendering भी अब भी संभव है
      यह ASP.NET MVC की markup language है, इसलिए “ASP.NET MVC Razor” से खोजें
    • हाल में C# से web development में दिलचस्पी हुई है
      अच्छा हो या बुरा, .NET में web applications बनाने का तरीका ASP.NET ही लगभग default answer जैसा लगता है
      alternatives की कमी थोड़ी suspicious है, लेकिन
      “ASP.NET Core in Action” के author Andrew Lock वाला podcast सुना, और वे विषय को अच्छी तरह जानने वाले लगे
      अभी किताब नहीं पढ़ी है, लेकिन शायद वही किताब हो सकती है जिसकी तलाश है
      1: https://dotnetcore.show/season-6/navigating-the-aspnet-core-...
      2: https://www.manning.com/books/asp-net-core-in-action-third-e...
    • थोड़ा niche है, लेकिन F# और Fable का combination बहुत powerful है
      server पर ASP.NET के ऊपर Giraffe चला सकते हैं, और यह C# जैसी performance देने वाली functional programming layer है
      front-end पर आप असली functional programming language में React लिख सकते हैं
      स्वाभाविक है कि front-end और back-end के बीच F# code भी share कर सकते हैं
    • मैंने करके सीखा, लेकिन reference के लिए कुछ resources लिख रहा हूँ
      किताबों में Mark J Price की “C# 12 and .NET 8 - Modern Cross-Platform Development Fundamentals - Eighth Edition: Start building websites and services with ASP.NET Core 8, Blazor, and EF Core 8”, और Xiaodi Yan की “Web API Development with ASP.NET Core 8: Learn techniques, patterns, and tools for building high-performance, robust, and scalable web APIs” हैं
      tutorials में YouTube पर IAmTimCorey और Shawn Wildermuth की series हैं
    • server-rendered UI के लिए Razor इस्तेमाल करने वाले resources ढूँढें, और शुरुआत में Blazor वाले resources से बचना बेहतर है
      .NET backend और JS front-end combination के लिए Minimal API इस्तेमाल करने वाले resources देखें
      MVC भी अच्छा है, लेकिन backward compatibility का बोझ ज़्यादा है, इसलिए Minimal API आया
  • annotations के इस spaghetti pile से बेहतर तरीका होना चाहिए
    modern .NET code देखते ही मेरी आँखें दुखने लगती हैं

    • वे attributes article में इस्तेमाल की गई benchmarking library से संबंधित हैं
      unit test और benchmarking code आम तौर पर कुछ हद तक spaghetti जैसा दिखता ही है
      फिर भी actual business logic में ऐसा PR मैं approve नहीं करूँगा
      अगर आपको सच में नापसंद है, तो AspNetCore जैसी चीज़ भी बिना किसी attribute को छुए इस्तेमाल कर सकते हैं
    • पता नहीं आप कौन सा .NET code देख रहे हैं
      मैं attributes का लगभग इस्तेमाल नहीं करता
  • Count(), First(), Last(), ElementAt(), Sum() जैसे methods पर chain खत्म होने पर और optimizations संभव हैं, और उदाहरण के लिए OrderBy(criteria).First() को Min(criteria) की तरह execute होने के लिए optimize किया जा सकता है—यह हिस्सा उपयोगी हो सकता है
    लेकिन शुरुआत से ही बेहतर code लिखना सही है
    dynamically generated chains के लिए यह interesting होगा, लेकिन अपने हाथ से लिखे code में अगर ऐसी operations कर रहे हैं तो यह थोड़ा टेढ़ा positive reinforcement जैसा लगता है
    library inefficient patterns को पहचानकर ठीक कर रही है
    कम से कम उम्मीद है कि underlying code सुधारने का feedback मिले