استدعاء طريقة حظر غير مناسبة: كيفية إصلاحه في Kotlin

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

«استدعاء طريقة حظر غير مناسبة»: عندما يوبخك Kotlin ولا تفهم السبب

\n\n

أنت تكتب بلغة Kotlin، وتستخدم الكوروتينات، كل شيء يبدو مثالياً. وفجأة - بام! - المترجم أو المحلل الثابت (مثل IntelliJ IDEA) يصدر تحذيراً: «استدعاء طريقة حظر غير مناسبة». هل هذا مألوف؟ إذا رأيت هذه الرسالة مرة واحدة على الأقل، فأنت تعلم: أنها تظهر في أكثر الأوقات غير المناسبة. وإذا لم ترها - فاعتبر نفسك محظوظاً، ولكن من الأفضل أن تستعد مسبقاً.

\n\n

هذا الخطأ ليس مجرد نزوة من بيئة التطوير. إنها إشارة: أنت تفعل شيئاً قد "يقتل" أداء تطبيقك. في هذه المقالة، سنشرح ما يعنيه هذا التحذير، ولماذا يحدث، والأهم من ذلك - كيف نجعل "استدعاء طريقة حظر غير مناسبة" مناسباً (أي ملائماً). سنقارن بين ثلاثة أساليب، ونكتب كوداً بلغة Kotlin، ونكتشف متى تكون كل طريقة أفضل. هيا بنا!

\n\n

ما هو «استدعاء طريقة حظر غير مناسبة»؟

\n\n

باختصار: Kotlin (ونظامه البيئي) مبني على فكرة التنفيذ غير المحظور. عندما تستخدم الكوروتينات، يُفترض أنك لن "توقف" الخيط باستدعاءات مثل Thread.sleep() أو InputStream.read(). هذا يحظر الخيط، بينما الكوروتينات، على العكس، يجب أن تحرره.

\n\n

مثال نموذجي - استدعاء Thread.sleep(1000) داخل كوروتين. يرى المحلل هذا ويصرخ: «مرحباً! أنت تحظر الخيط! استخدم delay()!». لكن المشكلة ليست فقط في sleep. أي استدعاء يمكن أن يحظر الخيط (قراءة من ملف، العمل مع قاعدة بيانات، طلب HTTP متزامن) يمكن أن يسبب هذا التحذير.

\n\n

لماذا هذا سيء؟ لأن الكوروتينات تعمل على مجموعة من الخيوط. إذا تم حظر خيط واحد، لا يمكنه تنفيذ كوروتينات أخرى. في أسوأ الحالات، قد تتعرض "لمجاعة" الخيوط وانخفاض في الأداء.

\n\n

مقارنة الأساليب: كيفية إصلاح الاستدعاء المحظور

\n\n

سننظر في ثلاثة سيناريوهات حيث يحدث الخطأ، ونوضح كيفية تجاوزه. لكل أسلوب سيكون هناك مثال على كود بلغة Kotlin وتحليل للإيجابيات والسلبيات. في النهاية - جدول ملخص.

\n\n

الأسلوب 1: استخدام Dispatchers.IO

\n\n

الطريقة الأبسط والأكثر توصية - لف الكود المحظور في withContext(Dispatchers.IO). هذا الموزع مصمم خصيصاً لعمليات الإدخال/الإخراج المحظورة.

\n\n
import kotlinx.coroutines.*\n\nsuspend fun readFile(path: String): String = withContext(Dispatchers.IO) {\n    // استدعاء محظور (مثل قراءة ملف)\n    java.io.File(path).readText()\n}\n\nfun main() = runBlocking {\n    val content = readFile("example.txt")\n    println(content)\n}
\n\n

الإيجابيات:

\n
    \n
  • الحد الأدنى من التغييرات في الكود.
  • \n
  • فصل واضح: يتم تنفيذ الكود المحظور على مجموعة خيوط منفصلة.
  • \n
  • لا يتطلب مكتبات خارجية.
  • \n
\n\n

السلبيات:

\n
    \n
  • لا يزال يحظر الخيط (وإن لم يكن الخيط الرئيسي).
  • \n
  • مع عدد كبير من الاستدعاءات المتزامنة، قد يستنفد مجموعة الخيوط (افتراضياً 64 خيطاً).
  • \n
\n\n

متى تستخدم: إذا كان لديك عمليات حظر نادرة (مثل تحميل التكوين عند بدء التشغيل) أو لا يمكنك تغيير المكتبة.

\n\n

الأسلوب 2: الاستبدال بنظائر غير محظورة

\n\n

الخيار المثالي، ولكن ليس ممكناً دائماً - استبدال الاستدعاء المحظور بنسخته غير المحظورة. على سبيل المثال، بدلاً من Thread.sleep() استخدم delay()، بدلاً من عميل HTTP المتزامن - غير المتزامن (Ktor, OkHttp مع الكوروتينات).

\n\n
import kotlinx.coroutines.*\n\nsuspend fun fetchData(): String {\n    // تأخير غير محظور\n    delay(1000)\n    // طلب HTTP غير متزامن (مثال مع Ktor)\n    return httpClient.get("https://api.example.com/data").body()\n}\n\nfun main() = runBlocking {\n    val data = fetchData()\n    println(data)\n}
\n\n

الإيجابيات:

\

المدونات

توصيات الكتب