Async و Await في لغة C#: إنقاذ التطبيق من "التجميد"
\n\nهل سبق لك أن قمت بتشغيل برنامج بلغة C#، وضغطت على زر، وتجمدت الواجهة لعدة ثوانٍ؟ أو ربما توقف خادمك عن الاستجابة للطلبات الجديدة أثناء معالجة طلب "ثقيل" واحد؟ مألوف؟ هذه هي المشكلة الكلاسيكية للكود المتزامن، حيث يتم حظر تيار التنفيذ في انتظار اكتمال عملية (قراءة ملف، استعلام قاعدة بيانات، استدعاء HTTP).
\n\nحل هذه المشكلة هو البرمجة غير المتزامنة. وفي لغة C#، الأدوات الرئيسية لذلك هي الكلمات المفتاحية async و await. إذا كنت قد تساءلت يومًا: "كيف ومتى تستخدم async و await؟" - فقد وصلت إلى المكان الصحيح. في هذا الدليل التعليمي، سنشرح كل شيء من الأساسيات إلى أفضل الممارسات، حتى تتمكن من كتابة كود سريع وسريع الاستجابة وقابل للتوسع.
هذه المادة مبنية على سؤال شائع حقيقي من Stack Overflow، حصل على آلاف المشاهدات. قمنا بتكييفه لمحتوى تعليمي، مع إضافة أمثلة على الكود وشروحات واضحة.
\n\nما هما async و await؟ بكلمات بسيطة
\n\nتخيل أنك طاهٍ (برنامجك). تحتاج إلى طهي العشاء. أحد الأطباق هو الحساء، الذي يجب أن يغلي لمدة 30 دقيقة. في العالم المتزامن، ستقف أمام الموقد وتنتظر فقط حتى ينضج الحساء، دون فعل أي شيء. أمر سخيف، أليس كذلك؟
\n\nعدم التزامن هو عندما تضع الحساء ليغلي (async) وبدون انتظار، تبدأ في تقطيع السلطة، وترتيب الطاولة، والقيام بأمور أخرى. عندما يصبح الحساء جاهزًا، تعود إليه (await). أنت لا تضيع الوقت - أنت فعال.
- \n
async- معدّل للطريقة يخبر المترجم: "هذه الطريقة تحتوي على عمليات غير متزامنة. لا تحجب التيار عندما أواجهawait". \n await- عامل يتم تطبيقه على مهمة (Task). يقول: "أوقف تنفيذ هذه الطريقة مؤقتًا حتى تكتمل المهمة، لكن لا تحجب التيار. بمجرد اكتمال المهمة، استمر في التنفيذ من هذه النقطة". \n
هام: await لا يحجب التيار. إنه يعيد التحكم إلى الكود المستدعي، ويستمر التيار في أداء عمل آخر.
متى تستخدم async و await؟
\n\nهذا هو السؤال الأكثر شيوعًا. الإجابة بسيطة: دائمًا عندما تقوم بعملية قد تستغرق وقتًا طويلاً (عمليات مرتبطة بالإدخال/الإخراج I/O-bound)، ولا تريد حجب التيار.
\n\nإليك السيناريوهات النموذجية:
\n- \n
- طلبات الشبكة: استدعاءات HTTP (HttpClient)، العمل مع WebSocket. \n
- العمل مع الملفات: قراءة/كتابة ملفات كبيرة، العمل مع التدفقات. \n
- استعلامات قواعد البيانات: Entity Framework، ADO.NET، Dapper. \n
- العمل مع خدمات الويب: WCF، REST API. \n
- أي عمليات إدخال/إخراج (I/O): الوصول إلى القرص، الشبكة، الطابعة. \n
متى لا يجب استخدام async و await؟
\n- \n
- العمليات المرتبطة بوحدة المعالجة المركزية (CPU-bound): إذا كانت مهمتك تتطلب حسابات مكثفة (عرض ثلاثي الأبعاد، معالجة فيديو، حسابات رياضية معقدة)، فإن
async/awaitلن يساعد. هنا يجب استخدامTask.RunأوParallelللتوازي على عدة أنوية للمعالج. \n - في منشئات الفئات (Constructors): لا يمكن أن تكون المنشئات غير متزامنة. استخدم طرق المصنع (
public static async Task<MyClass> CreateAsync()). \n - في دوال الحصول/تعيين الخصائص (Getters/Setters): هي أيضًا لا يمكن أن تكون غير متزامنة. استخدم الطرق. \n
كيف يعمل هذا؟ تحليل مع مثال على الكود
\n\nدعنا نلقي نظرة على كود حقيقي. تخيل أننا نقوم بتحميل بيانات من خادم بعيد.
\n\nمثال سيء (متزامن)
\npublic string GetDataFromWeb()\n{\n usi