C# / دليل حلول تحريري

حل الحجب غير المتزامن وفجوات الإلغاء

حدد الاستمرار أو العملية التي لا تتقدم ثم أصلح تركيب اللاتزامن وملكية الاكتمال.

وقت القراءة التقريبي: 3 دقيقةتاريخ مراجعة المحتوى

قاعدة معرفة للقراءة فقط · بلا تعليقات عامة

تعرّف على الأعراض

قد تتجمد الواجهة عند .Result أو Wait، أو لا ينتهي طلب، أو يعود الإلغاء والعمل المملوك مستمر. قد يعمل الحجب في الطرفية ويعلق داخل سياق مزامنة مقيد. ويختلف جوع الخيوط عن عملية تابعة لا تلغى؛ فلا يشخص السبب من عرض واحد.

افهم الأسباب المحتملة

  • قد يشغل الحجب السياق الذي يحتاجه الاستمرار. تزيل المهام المهملة وasync void الملاحظة العادية للاكتمال. لا يقطع رمز غير ممرر إلى الانتظار حجبا، ويطلب Cancel التعاون ولا ينتظر. ولا تلغي WhenAll الأخوات أو تحد عدد المطلق تلقائيا.

1. تصنيف حد الحجب

افحص مكدسات المهام والخيوط محليا وحدد علاقة الانتظار. هل يملك المستدعي سياق واجهة أو سياقا خاصا؟ هل ينتظر قفلا أم حُجبت الخيوط المتاحة؟ اختزل ببيانات اصطناعية. لا يثبت انتهاء برنامج طرفية سلامة .Result في سياق التطبيق الحقيقي.

2. حفظ سلسلة استدعاء قائمة على await

فضل طرقا تعيد مهاما وانتظر عبر سلسلة المالك بدلا من الحجب. قد تمنع ConfigureAwait(false) التقاط السياق لكنها ليست علاجا عاما ولا تفرض خيطا جديدا. قد تحتاج الواجهة سياقها وتختار المكتبة سياسة مقصودة. لا تجعل Task.Run غلافا افتراضيا لإخفاء حجب إدخال غير متزامن.

3. تمرير الإلغاء للعملية الفعلية

يبدأ المثال انتظارا واعيا بالرمز ويلغيه ثم ينتظر المهمة قبل تقرير الاكتمال. يربط المرشح الإلغاء بالمصدر المقصود. لا يستخدم خدمة خارجية ولا يبقى التأخير المفتوح بعد طلب الإلغاء المؤكد. لا تطبع joined إلا بعد نهاية المهمة المملوكة.

csharp إلغاء يتبعه اكتمال ملحوظ
using System;
using System.Threading;
using System.Threading.Tasks;

using var source = new CancellationTokenSource();
Task work = WaitAsync(source.Token);
source.Cancel();
try
{
    await work;
}
catch (OperationCanceledException exception) when (exception.CancellationToken == source.Token)
{
    Console.WriteLine("cancelled");
}
Console.WriteLine("joined");

static Task WaitAsync(CancellationToken token) => Task.Delay(Timeout.Infinite, token);
الناتج المتوقع
cancelled
joined

ينتهي التأخير بالإلغاء ويسبق انتظاره رسالة joined.

4. إبقاء الاعتمادات حية حتى نهاية المهام

تقصر using حول الإطلاق إذا استمر استخدام المورد. انتظر ضمن عمره أو انقل ملكيته. ألغ ولاحظ كل ما بدأ عند العودة المبكرة. تخلص من السمافور ومصدر الإلغاء بعد المستعيرين؛ فقد يضيف التخلص الأول ObjectDisposedException إلى التعليق الأصلي.

5. تحديد القبول والآثار الجزئية

يحد السمافور النشاط لا صفا منتظرا بلا حد، وتركب WhenAll الاكتمال فقط. حد القبول والتنفيذ معا. حدد النجاح الجزئي بعد الاعتماد وعدم تكرار الإعادات؛ فلا يتراجع الإلغاء عن أثر خارجي. وقد تؤخر زيادة إعداد الخيوط دون تشخيص عيب العمر فقط.

تحقق من نجاح الإصلاح

يجب أن يطبع المثال cancelled ثم joined وينتهي سريعا دون تأكيد قائم على النوم. اختبر الإلغاء قبل البدء وأثناء الانتظار والنجاح وفشل التابع والتنظيف. تكشف مهلة الاختبار عدم الانتهاء ولا تستبدل مزامنة التنفيذ. وافحص الإصلاح في سياق التطبيق الفعلي.

امنع تكرار المشكلة

  • أعد المهام ولاحظها وتجنب async void خارج الأحداث المطلوبة، ومرر الرموز وعين مسؤول التوقف والانتظار. راجع الخروج المبكر وترتيب التخلص وصرح بالسياق واحفظ فئات الخطأ بدلا من تحويل كل استثناء إلى إلغاء.

المراجع الرسمية