मुख्य कंटेंट तक स्किप करें

Valkarn Tasks क्यों चुनें

Unity के लिए शून्य-आवंटन async/await। UniTask से तेज़। Awaitable से स्मार्ट।


समस्या: Unity में async टूटी हुई है

Unity डेवलपर्स को हर जगह असंक्रामक ऑपरेशनों की जरूरत होती है: सीन लोड करना, एसेट डाउनलोड करना, एनिमेशन का इंतजार करना, स्पॉन में देरी करना, सर्वर से संचार करना। आज, विकल्प हैं:

विकल्पसमस्या
Coroutinesकोई रिटर्न वैल्यू नहीं, कोई एरर हैंडलिंग नहीं, कोई कैंसलेशन नहीं, कोई कम्पोजीशन नहीं
System.Threading.Tasksहर async कॉल पर आवंटन (~144–232 बाइट्स), GC ट्रिगर करता है, Unity लाइफसाइकिल की कोई जागरूकता नहीं
UniTaskअच्छा — लेकिन: 18 मिनट के बाद टोकन टकराव, कम्पाइल-टाइम डायग्नोस्टिक्स नहीं, फिनलाइज़र-निर्भर एरर रिपोर्टिंग
Unity Awaitable (2023+)क्लास-आधारित (आवंटन करता है), कोई कम्बाइनर नहीं, कोई चैनल नहीं, कोई टेस्टिंग सपोर्ट नहीं

Valkarn Tasks इन सभी समस्याओं को एक ही सोर्स-जेनरेटेड, शून्य-आवंटन पैकेज में हल करता है।


शून्य आवंटन — हर बाइट क्यों मायने रखती है

गेम्स के लिए आवंटन का अर्थ

हर new object(), new List<T>(), या async Task कॉल मैनेजड हीप पर आवंटन करती है, जिसे Garbage Collector ट्रैक करता है। Unity Boehm GC उपयोग करता है जिसमें दो गंभीर समस्याएं हैं:

  1. Stop-the-world पॉज़ — जब GC चलता है, आपका गेम फ्रीज हो जाता है। 60 fps पर 2 ms का पॉज़ आपके फ्रेम बजट का 12% खाता है; 120 fps (VR) पर 24%।
  2. अप्रत्याशित टाइमिंग — GC बॉस फाइट, कटसीन, या कॉम्पीटिटिव मैच के दौरान ट्रिगर हो सकता है।

Valkarn Tasks क्या अलग करता है

परिदृश्यSystem.TaskUniTaskValkarn Tasks
async Method() — सिंक्रोनसली पूर्ण144 बाइट्स0 बाइट्स0 बाइट्स
async Method() — एक बार सस्पेंड232+ बाइट्स0 बाइट्स (pooled)0 बाइट्स (pooled)
WhenAll(a, b)232 बाइट्स0 बाइट्स (pooled)0 बाइट्स (source-gen pooled)
WhenAny(a, b)144 बाइट्स72 बाइट्स0 बाइट्स
Promise (मैन्युअल पूर्णता)144 बाइट्स104 बाइट्स88 बाइट्स
Pooled Promise (पुन: उपयोगी)144 बाइट्स0 बाइट्स0 बाइट्स

50–100 async ऑपरेशनों के साथ एक सामान्य गेम फ्रेम में, System.Task 7–23 KB कचरा उत्पन्न करता है। Valkarn Tasks शून्य उत्पन्न करता है।

इसका आपके गेम पर क्या प्रभाव पड़ता है

  • कोई GC स्टटरिंग नहीं — async ऑपरेशनों से बिना रुकावट लॉक्ड फ्रेमरेट
  • VR-सुरक्षित — GC स्पाइक्स के बिना 90/120 fps लक्ष्य
  • मोबाइल-फ्रेंडली — सीमित RAM डिवाइस पर कम मेमोरी प्रेशर
  • कंसोल-सर्टिफाइड — पूर्वानुमेय मेमोरी व्यवहार सर्टिफिकेशन आवश्यकताओं को पास करने में मदद करता है

प्रदर्शन — सर्वश्रेष्ठ के मुकाबले बेंचमार्क

बेंचमार्क: BenchmarkDotNet v0.14.0, .NET 9.0, Intel Core i7-10875H।

Core async/await — ValueTask से 2× तेज़

बेंचमार्कValueTaskUniTaskValkarn Tasksvs ValueTask
100 टास्क बल्क956 ns508 ns489 ns1.95×
1,000 टास्क बल्क9,697 ns5,016 ns4,728 ns2.05×
CancellationToken के साथ38.8 ns36.2 ns29.6 ns1.31×
एक्सेप्शन हैंडलिंग10,399 ns8,247 ns9,248 ns1.12×

सभी पाथ: 0 बाइट्स आवंटित

कम्बाइनर — Task से 9.6× तक तेज़

बेंचमार्कTaskUniTaskValkarn Tasksvs Task
WhenAll (2 टास्क)117 ns / 232B13.6 ns / 0B12.1 ns / 0B9.6×
WhenAll (5 टास्क)156 ns / 272B25.1 ns / 0B25.3 ns / 0B6.2×
WhenAny (2 टास्क)39.0 ns / 144B60.0 ns / 72B11.6 ns / 0B3.4×
Pooled Promise59.5 ns / 144B53.6 ns / 0B38.3 ns / 0B1.55×

WhenAny UniTask से 5.2× तेज़ है और शून्य बाइट्स आवंटित करता है।

ऑब्जेक्ट पूल — 4.3 नैनोसेकंड

ऑपरेशनसमयआवंटन
मेन-थ्रेड फास्ट-स्लॉट रेंट + रिटर्न4.3 ns0 बाइट्स
क्रॉस-थ्रेड Treiber स्टैक~15 ns0 बाइट्स

मेन थ्रेड पर शून्य एटॉमिक ऑपरेशन — IL2CPP के लिए महत्वपूर्ण जहां Volatile.Read 9.2× धीमा है।

वास्तविक दुनिया का प्रभाव (60 fps पर 50 async ops/फ्रेम)

लाइब्रेरीसमय/फ्रेमफ्रेम बजटGC/सेकंड
System.Task~48 µs0.29%~430 KB/s
UniTask~25 µs0.15%~3.6 KB/s
Valkarn Tasks~24 µs0.14%0 KB/s

10 मिनट में, System.Task ~258 MB async कचरा उत्पन्न करता है। Valkarn Tasks शून्य उत्पन्न करता है।


वे फीचर्स जो कोई अन्य लाइब्रेरी नहीं देती

स्वचालित लाइफसाइकिल कैंसलेशन

public partial class EnemySpawner : MonoBehaviour
{
async ValkarnTask Start()
{
while (true)
{
await ValkarnTask.Delay(3000);
SpawnWave();
}
// जब यह GameObject नष्ट होता है तो स्वचालित रूप से कैंसल।
// कोई CancellationToken नहीं। कोई मेमोरी लीक नहीं। कोई ज़ॉम्बी टास्क नहीं।
}
}

नष्ट होने के बाद चलने वाली async मेथड्स से MissingReferenceException अब नहीं। कोई मैन्युअल OnDestroy क्लीनअप नहीं। कोई भूला हुआ CancellationTokenSource डिस्पोज़ल नहीं।

क्रिटिकल सेक्शन

async ValkarnTask SaveProgress()
{
var data = await LoadPlayerData(); // कैंसल योग्य

await using (ValkarnTask.Critical())
{
await db.Insert(data); // GO नष्ट होने पर भी पूर्ण होता है
await db.Commit();
} // पेंडिंग कैंसलेशन अब लागू होता है

await SendNotification(); // फिर से कैंसल योग्य
}

डेटाबेस राइट्स, नेटवर्क रिक्वेस्ट और फाइल सेव्स तब भी पूर्ण होते हैं जब प्लेयर छोड़ देता है या सीन अनलोड होती है। कोई करप्ट सेव्स नहीं। कोई आधी लिखी analytics नहीं। कोई खोई हुई रसीदें नहीं।

कम्पाइल-टाइम डायग्नोस्टिक्स

डायग्नोस्टिकयह क्या पकड़ता है
TT001ValkarnTask का डबल-अवेट (use-after-free बग)
TT002टास्क को अवेट करना भूलना (साइलेंट फेल्योर)
TT012कैंसलेशन चेक के बिना async लूप (ज़ॉम्बी लूप)
TT013रिटर्न किया लेकिन अवेट नहीं किया टास्क (fire-and-forget बग)
TT016बिना await के async मेथड (अनावश्यक ओवरहेड)
TT017ValkarnTask<T> पर [FireAndForget] (एक परिणाम को नज़रअंदाज़ करना)

IDE में लाल अंडरलाइन के रूप में पकड़े गए बग — परीक्षण के 20 मिनट बाद रनटाइम क्रैश नहीं।

Result<T> — try/catch के बिना एरर हैंडलिंग

var result = await loadTask.AsResult();

if (result.Succeeded) Use(result.Value);
else if (result.IsCanceled) ShowRetryDialog();
else Debug.LogError(result.Error);

हर एरर पाथ स्पष्ट है। कोई निगली हुई exceptions नहीं। कोई मिसिंग हैंडलर नहीं।

Backpressure के साथ चैनल

var channel = ValkarnTask.Channel.CreateBounded<EnemySpawnRequest>(capacity: 10);

// प्रोड्यूसर (गेम लॉजिक)
await channel.Writer.WriteAsync(new EnemySpawnRequest { type = EnemyType.Dragon });

// कंज़्यूमर (स्पॉन सिस्टम)
await foreach (var request in channel.Reader.ReadAllAsync())
await SpawnEnemy(request);

सिस्टम को साफ़ तरीके से अलग करें। स्पॉनिंग को रेट-लिमिट करें। नेटवर्क मैसेज कतारबद्ध करें। इनपुट इवेंट बफर करें। जब कंज़्यूमर नहीं रख सकता तो प्रोड्यूसर धीमा हो जाता है — मेमोरी स्पाइक्स को रोकता है।

TestClock के साथ डिटर्मिनिस्टिक टेस्टिंग

[Test]
public void Respawn_WaitsThreeSeconds()
{
var clock = new TestClock();
var task = spawner.RespawnEnemy();

clock.Advance(TimeSpan.FromSeconds(2));
Assert.IsFalse(task.IsCompleted);

clock.Advance(TimeSpan.FromSeconds(1));
Assert.IsTrue(task.IsCompleted);
}

टाइम-डिपेंडेंट लॉजिक तुरंत टेस्ट करें। टेस्ट में yield return new WaitForSeconds(3) नहीं। कोई फ्लेकी CI टाइमिंग नहीं।

जेनरेशनल टोकन सेफ्टी

UniTask एक short टोकन (16-बिट) उपयोग करता है। 65,536 पूल साइकिल (~18 मिनट सक्रिय async काम) के बाद, एक पुराना संदर्भ चुपके से दूसरे टास्क का परिणाम पढ़ता है — एक use-after-free बग जिसे reproduce करना लगभग असंभव है।

Valkarn Tasks प्रति पूल स्लॉट एक uint जेनरेशन काउंटर उपयोग करता है: टकराव से पहले 4,294,967,296 साइकिल प्रति स्लॉट। किसी भी वास्तविक परिदृश्य में असंभव।


माइग्रेशन मिनटों में, हफ्तों में नहीं

UniTask से

चरण 1: Valkarn Tasks इंस्टॉल करें
चरण 2: IDE में UniTask उपयोग पर पीले बल्ब दिखते हैं
चरण 3: राइट-क्लिक → "Fix all occurrences in Solution" (Ctrl+.)
चरण 4: UniTask पैकेज संदर्भ हटाएं

15 माइग्रेशन डायग्नोस्टिक्स (MIG001–MIG015) हर UniTask API को स्वचालित रूप से कवर करते हैं। 500–2,000 async मेथड वाला एक सामान्य प्रोजेक्ट 5 मिनट से कम में माइग्रेट होता है। 95%+ पूरी तरह स्वचालित।

Unity Awaitable से

वही एक-क्लिक माइग्रेशन:

  • async Awaitableasync ValkarnTask
  • Awaitable.NextFrameAsync()ValkarnTask.NextFrame()
  • Awaitable.BackgroundThreadAsync()ValkarnTask.SwitchToThreadPool()
  • Awaitable.MainThreadAsync() → हटाया गया (Valkarn डिफ़ॉल्ट रूप से मेन थ्रेड पर चलता है)

तुलना मैट्रिक्स

फीचरSystem.TaskUniTaskAwaitableValkarn Tasks
शून्य-आवंटन सिंक पाथनहींहाँनहींहाँ
शून्य-आवंटन कम्बाइनरनहींनहींनहींहाँ (source gen)
Struct-आधारितनहींहाँनहींहाँ
लाइफसाइकिल ऑटो-कैंसलनहींमैन्युअलआंशिकस्वचालित
कोई सिब्लिंग कैंसलेशन नहींनहींनहींनहींहाँ
क्रिटिकल सेक्शननहींनहींनहींहाँ
Result<T> (थ्रो नहीं)नहींआंशिकनहींहाँ
TestClockनहींनहींनहींहाँ
Job System ब्रिजनहींनहींनहींहाँ
कम्पाइल-टाइम डायग्नोस्टिक्सनहींनहींनहींहाँ (17 नियम)
बाउंडेड पूल + ट्रिमनहींनहींलागू नहींहाँ
डिटर्मिनिस्टिक एरर रिपोर्टनहींनहीं (finalizer)आंशिकहाँ (pool return)
पूर्ण चैनलहाँ (.NET)न्यूनतमनहींहाँ
Awaitable ब्रिजलागू नहींन्यूनतमनेटिवपारदर्शी
IL2CPP-ऑप्टिमाइज़्ड पूलिंगनहींनहीं (हर op पर Volatile)लागू नहींहाँ (शून्य atomics)
टोकन टकराव सेफ्टीलागू नहीं18 मिनट (short)लागू नहींकभी नहीं (uint gen)
UniTask से ऑटो-माइग्रेशनलागू नहींलागू नहींलागू नहींहाँ (15 फिक्स)
Awaitable से ऑटो-माइग्रेशनलागू नहींलागू नहींलागू नहींहाँ (8 फिक्स)

आपके गेम को ऐसी async चाहिए जो न रुके।