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

फीचर्स

Valkarn Tasks के लिए पूर्ण फीचर संदर्भ।


मूल async प्रिमिटिव

ValkarnTask स्ट्रक्चर

एक शून्य-आवंटन, struct-आधारित async रिटर्न टाइप जो UniTask और Unity के Awaitable दोनों को प्रतिस्थापित करता है।

async ValkarnTask LoadLevel() { ... }
async ValkarnTask<int> CountEnemies() { ... }
  • शून्य-आवंटन सिंक्रोनस फास्ट पाथ — यदि मेथड कभी सस्पेंड हुए बिना पूर्ण होती है, तो हीप आवंटन शून्य होता है।
  • पूल्ड async पाथ — यदि मेथड सस्पेंड होती है, तो स्टेट मशीन रनर एक बाउंडेड, श्रिंकेबल पूल से लिया जाता है। शून्य boxing, स्वचालित ट्रिमिंग के साथ बाउंडेड पूल।
  • IL2CPP-first पूलिंग — मेन थ्रेड पर पूल ऑपरेशन शून्य atomics उपयोग करते हैं। IL2CPP Mono की तुलना में Volatile को 9.2× और Interlocked को 2.9× पेनल्टी देता है; Valkarn हॉट पाथ पर दोनों से बचता है।
  • जेनरेशनल टोकन सेफ्टी — प्रति पूल स्लॉट एक uint जेनरेशन काउंटर। टकराव से पहले प्रति स्लॉट 4,294,967,296 साइकिल — व्यवहार में असंभव। (UniTask एक short टोकन उपयोग करता है: ~18 मिनट सक्रिय async काम के बाद टकराव।)

Result<T> — exception-मुक्त एरर हैंडलिंग

var result = await loadTask.AsResult();

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

Result<T> और Result readonly struct वैल्यू हैं जो बिना थ्रो किए टास्क के परिणाम को दर्शाते हैं। दोनों bool में इम्प्लिसिट कनवर्शन सपोर्ट करते हैं (सफल होने पर true)।

मैन्युअल कम्प्लीशन सोर्स

var promise = new ValkarnTask.Promise<string>();
promise.TrySetResult("done");
string value = await promise.Task;

TrySetResult, TrySetException, और TrySetCanceled को सपोर्ट करता है। Finalizer-आधारित अनऑब्ज़र्व्ड एक्सेप्शन रिपोर्टिंग सुनिश्चित करती है कि एरर कभी चुपके से न खो जाएं।

पूल्ड कम्प्लीशन सोर्स

दोहराने वाले पैटर्न के लिए ऑटो-रीसेट पूल्ड वेरिएंट (चैनल और कम्बाइनर द्वारा आंतरिक रूप से उपयोग):

var source = ValkarnTask.PooledPromise<int>.Create(out uint token);
source.TrySetResult(42);
int value = await source.Task; // source स्वचालित रूप से पूल में वापस जाता है

Awaitable ब्रिज

Unity के Awaitable के साथ पारदर्शी इंटरऑप — कोई मैन्युअल कनवर्शन नहीं:

async ValkarnTask LoadGame()
{
await SceneManager.LoadSceneAsync("Level2"); // Unity Awaitable — सीधे काम करता है
await Resources.LoadAsync<Texture2D>("hero"); // Unity Awaitable — सीधे काम करता है
await ValkarnTask.Delay(1000); // Valkarn नेटिव
}

सोर्स जेनरेटर Awaitable awaits का पता लगाता है और एडेप्टर स्वचालित रूप से जेनरेट करता है।


लाइफसाइकिल कैंसलेशन

स्वचालित (सोर्स-जेनरेटेड)

क्लास को partial मार्क करें — सोर्स जेनरेटर बाकी करता है:

public partial class EnemySpawner : MonoBehaviour
{
async ValkarnTask Start()
{
while (true)
{
await ValkarnTask.Delay(3000);
SpawnWave();
// जब यह GameObject नष्ट होता है तो स्वचालित रूप से कैंसल।
}
}
}
  • MonoBehaviourdestroyCancellationToken से बाउंड
  • ScriptableObject — एप्लिकेशन लाइफटाइम से बाउंड
  • Plain class — कोई स्वचालित बाइंडिंग नहीं (मैन्युअल टोकन आवश्यक)

ऑप्ट-आउट

[NoAutoCancel]
async ValkarnTask BackgroundSync()
{
await SyncToServer(); // नष्ट होने पर ऑटो-कैंसल नहीं
}

मैन्युअल CancellationToken ओवरराइड

एक स्पष्ट CancellationToken पास करना ऑटो-इंजेक्टेड लाइफसाइकिल टोकन को ओवरराइड करता है:

async ValkarnTask DoWork(CancellationToken ct)
{
await ValkarnTask.Delay(1000, ct);
}

कोई सिब्लिंग कैंसलेशन नहीं

टास्क कभी सिब्लिंग टास्क को कैंसल नहीं करते। WhenAll सभी टास्क का इंतजार करता है; WhenAny पहला परिणाम लौटाता है लेकिन हारने वाले टास्क चलते रहते हैं। यह डेटा करप्शन को रोकता है जब टास्क के साइड इफेक्ट होते हैं।


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

उन ऑपरेशनों के लिए जो लाइफसाइकिल कैंसलेशन द्वारा बाधित नहीं होनी चाहिए:

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

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

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

क्रिटिकल सेक्शन के अंदर, कैंसलेशन स्थगित है — नज़रअंदाज़ नहीं। जब सेक्शन समाप्त होता है, पेंडिंग कैंसलेशन लागू होता है।


कम्बाइनर

WhenAll (टाइप्ड)

// डायरेक्ट — किसी टास्क के फेल होने पर थ्रो करता है
var (enemies, map) = await ValkarnTask.WhenAll(LoadEnemies(), LoadMap());

// सेफ — नॉन-थ्रोइंग बिहेवियर के लिए AsResult() से रैप करें
var (a, b) = await ValkarnTask.WhenAll(
LoadEnemies().AsResult(), LoadMap().AsResult());

जब सभी टास्क पहले से पूर्ण हों तो शून्य-आवंटन सिंक फास्ट पाथ। IEnumerable<ValkarnTask<T>> ओवरलोड आंतरिक एरे के लिए ArrayPool<T> उपयोग करता है।

WhenAll (void)

await ValkarnTask.WhenAll(SaveA(), SaveB(), SaveC());
await ValkarnTask.WhenAll(taskList); // IEnumerable<ValkarnTask>

WhenAny

var (winnerIndex, result) = await ValkarnTask.WhenAny(DownloadFromA(), DownloadFromB());

पहला पूर्ण परिणाम लौटाता है। हारने वाले टास्क स्वाभाविक रूप से चलते रहते हैं।

Fire-and-forget

SendAnalytics("event").Forget();

[FireAndForget]
async ValkarnTask SendAnalytics(string eventName) { ... }
// कॉलर को .Forget() की जरूरत नहीं — कोई वार्निंग जेनरेट नहीं

.Forget() एरर को ValkarnTask.UnobservedException पर रूट करता है। कभी चुपके से नहीं निगला जाता।

AsNonGeneric

ValkarnTask voidTask = typedTask.AsNonGeneric();

समय और देरी

await ValkarnTask.Delay(1000);                                    // मिलीसेकंड
await ValkarnTask.Delay(TimeSpan.FromSeconds(2)); // TimeSpan
await ValkarnTask.Delay(1000, DelayType.UnscaledDeltaTime); // timescale नज़रअंदाज़ करें
await ValkarnTask.Delay(1000, DelayType.Realtime); // Stopwatch-आधारित

await ValkarnTask.Yield(); // अगला PlayerLoop टिक
await ValkarnTask.Yield(PlayerLoopTiming.FixedUpdate); // विशिष्ट टाइमिंग
await ValkarnTask.NextFrame(); // गारंटीड अगला फ्रेम
await ValkarnTask.DelayFrame(5); // N फ्रेम

await ValkarnTask.WaitUntil(() => player.IsReady);
await ValkarnTask.WaitWhile(() => isLoading);

थ्रेड स्विचिंग

async ValkarnTask ProcessData()
{
var raw = await DownloadData();

await ValkarnTask.SwitchToThreadPool();
var processed = HeavyComputation(raw); // बैकग्राउंड थ्रेड

await ValkarnTask.SwitchToMainThread();
ApplyToGameObject(processed); // मेन थ्रेड
}

16 PlayerLoop टाइमिंग

ग्रुपटाइमिंग
InitializationInitialization, LastInitialization
EarlyUpdateEarlyUpdate, LastEarlyUpdate
FixedUpdateFixedUpdate, LastFixedUpdate
PreUpdatePreUpdate, LastPreUpdate
UpdateUpdate, LastUpdate
PreLateUpdatePreLateUpdate, LastPreLateUpdate
PostLateUpdatePostLateUpdate, LastPostLateUpdate
TimeUpdateTimeUpdate, LastTimeUpdate

सभी ऑपरेशन डिफ़ॉल्ट रूप से PlayerLoopTiming.Update उपयोग करते हैं जब तक अन्यथा निर्दिष्ट न हो।


चैनल

// अनबाउंडेड
var channel = ValkarnTask.Channel.CreateUnbounded<EnemySpawnRequest>();

// बाउंडेड — भरने पर backpressure
var channel = ValkarnTask.Channel.CreateBounded<LogEntry>(capacity: 100);

// मल्टी-कंज़्यूमर
var channel = ValkarnTask.Channel.CreateUnbounded<WorkItem>(multiConsumer: true);

// प्रोड्यूसर
await channel.Writer.WriteAsync(entry);
bool accepted = channel.Writer.TryWrite(entry);

// कंज़्यूमर
await foreach (var item in channel.Reader.ReadAllAsync())
Process(item);

// कम्प्लीशन
channel.Writer.Complete();
await channel.Reader.Completion;

डिटर्मिनिस्टिक टेस्टिंग (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);
}

सभी टाइम-डिपेंडेंट ऑपरेशन TimeProvider.Current से पढ़ते हैं। टेस्ट में, इसे TestClock से बदलें। AdvanceFrame() एक single player loop टिक सिमुलेट करता है।


Job System ब्रिज

var job = new PathfindingJob { start = a, end = b, results = results };
await job.ScheduleAsync();
// await के तुरंत बाद results NativeArray पठनीय है

await job.ScheduleParallelAsync(dataCount, batchSize); // IJobParallelFor

// कैंसलेशन — कैंसलेशन रिपोर्ट करने से पहले job handle पूर्ण करें (कोई job लीक नहीं)
await job.ScheduleAsync(cancellationToken);

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

कोडगंभीरताविवरण
TT001वार्निंगValkarnTask पर डबल-await / use-after-free
TT002एररasync ValkarnTask परिणाम एक्सप्रेशन स्टेटमेंट के रूप में उपयोग — await या .Forget() होना चाहिए
TT010इन्फोMonoBehaviour में async मेथड Destroy पर ऑटो-कैंसल
TT011वार्निंगWhenAll में अलग-अलग लाइफटाइम वाले टास्क हैं
TT012वार्निंगकैंसलेशन चेक के बिना async लूप (संभावित ज़ॉम्बी लूप)
TT013वार्निंगValkarnTask रिटर्न किया लेकिन कभी await नहीं और स्पष्ट रूप से डिस्कार्ड नहीं
TT014वार्निंगमैन्युअल CancellationToken पैरामीटर के बिना [NoAutoCancel]
TT015इन्फोValkarnTask के अंदर Awaitable await करना — ब्रिज एडेप्टर जेनरेट
TT016वार्निंगबिना await एक्सप्रेशन के async मेथड
TT017वार्निंगValkarnTask<T> पर [FireAndForget] — रिटर्न वैल्यू डिस्कार्ड करता है

पूल प्रबंधन

हर async मेथड रनर ValkarnPool<T> के माध्यम से पूल किया जाता है:

  • मेन थ्रेड — लॉक-फ्री स्टैक, शून्य atomics
  • बैकग्राउंड थ्रेड — CAS ऑपरेशन के साथ Treiber लॉक-फ्री स्टैक
  • फ्रेम-आधारित ट्रिमिंग — हर 300 फ्रेम (~5s at 60fps), अधिक ऑब्जेक्ट धीरे-धीरे रिलीज़ होते हैं
  • कभी नहीं घटाता कॉन्फिगर करने योग्य न्यूनतम से नीचे (डिफ़ॉल्ट: 8)

रनटाइम पर मॉनिटर करें:

foreach (var (type, size, maxSize) in ValkarnTask.GetPoolInfo())
Debug.Log($"{type}: {size}/{maxSize}");

ValkarnTaskSettings

ScriptableObject के माध्यम से कॉन्फिगर करें (Assets > Create > Valkarn > Tasks > Task Settings, Resources/ में रखें):

सेटिंगडिफ़ॉल्टविवरण
DefaultMaxPoolSize256प्रति पूल टाइप अधिकतम आइटम
MinPoolSize8इससे नीचे कभी ट्रिम न करें
TrimCheckInterval300ट्रिम चेक के बीच फ्रेम
TrimHysteresisCount2ट्रिमिंग से पहले लगातार चेक
TrimReleaseRatio0.25प्रति साइकिल रिलीज़ किया गया अधिक का अंश
EnableAutoCanceltrueMonoBehaviour टास्क को destroyCancellationToken से ऑटो-बाइंड
LogUnobservedCancellationsfalseअनऑब्ज़र्व्ड कैंसलेशन को वार्निंग के रूप में लॉग करें
MaxExceptionLogsPerFrame10प्रति फ्रेम एक्सेप्शन लॉग कैप

एरर हैंडलिंग

// अनऑब्ज़र्व्ड एक्सेप्शन — पूल रिटर्न पर डिटर्मिनिस्टिकली फायर
ValkarnTask.UnobservedException += ex =>
Debug.LogError($"Unobserved: {ex}");
  • WhenAll — पहला एक्सेप्शन थ्रो करता है, अतिरिक्त को UnobservedException पर रूट करता है
  • WhenAny — विजेता का एक्सेप्शन थ्रो होता है; हारने वालों की फॉल्ट UnobservedException पर जाती है
  • लाइफसाइकिल कैंसलेशन — OperationCanceledException डिफ़ॉल्ट रूप से सप्रेस (कॉन्फिगर करने योग्य)

फैक्ट्री मेथड

ValkarnTask.CompletedTask          // void, शून्य-आवंटन
ValkarnTask.FromResult<T>(value) // टाइप्ड, शून्य-आवंटन
ValkarnTask.FromException(ex) // फॉल्टेड
ValkarnTask.FromException<T>(ex)
ValkarnTask.FromCanceled() // कैंसल्ड
ValkarnTask.FromCanceled<T>()
ValkarnTask.Never // कभी पूर्ण नहीं होता (WhenAny के लिए sentinel)