0Pricing
Lua Academy · درس

حالة البرنامج التعاوني

تحقّق من حالة البرنامج التعاوني باستخدام coroutine.status: ‏running وsuspended وdead

حالة البرنامج التعاوني درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.

حالات الكوروتين الأربع

للكوروتينات أربع حالات ممكنة: معلّق (أُنشئ حديثًا أو نفّذ yield، وينتظر التشغيل)، وقيد التشغيل (ينفذ حاليًا)، وعادي (متوقف مؤقتًا للسماح لكوروتين آخر بالعمل)، ومنتهٍ (انتهى أو حدث فيه خطأ). استعلم عن الحالة باستخدام coroutine.status(co).

local co = coroutine.create(function()
  print(coroutine.status(coroutine.running()))  -- running
  coroutine.yield()
end)

print(coroutine.status(co))  -- suspended
coroutine.resume(co)          -- prints: running
print(coroutine.status(co))  -- suspended
coroutine.resume(co)
print(coroutine.status(co))  -- dead

حالة «عادي»

يدخل الكوروتين في حالة «عادي» عندما يستأنف كوروتينًا آخر. فهو ليس قيد التشغيل (لأن الكوروتين الآخر هو الذي يعمل)، وليس معلّقًا أيضًا، بل ينتظر حتى ينفذ الكوروتين المستأنَف yield. هذه الحالة نادرة، لكنها مهمة لفهم مخططات الكوروتينات المعقدة.

local inner, outer

inner = coroutine.create(function()
  print("outer status:", coroutine.status(outer))  -- normal
  coroutine.yield()
end)

outer = coroutine.create(function()
  coroutine.resume(inner)
end)

coroutine.resume(outer)
-- prints: outer status: normal

التحقق قبل الاستئناف

تحقّق دائمًا من حالة الكوروتين قبل استئنافه، ولا سيما داخل الحلقات. استئناف كوروتين منتهٍ خطأ. كما أن استئناف كوروتين قيد التشغيل خطأ أيضًا، لأنه قد يؤدي إلى استدعاء تكراري لا نهائي.

local function safeResume(co, ...)
  local status = coroutine.status(co)
  if status == "dead" then
    return false, "cannot resume dead coroutine"
  end
  if status == "running" then
    return false, "cannot resume running coroutine"
  end
  return coroutine.resume(co, ...)
end

الحالة بعد حدوث خطأ

عندما يرفع جسم الكوروتين خطأً غير معالَج، يعيد coroutine.resume القيمة false ورسالة الخطأ. وينتقل الكوروتين إلى الحالة «منتهٍ». ولا يمكن إعادة تشغيله؛ لذا يجب إنشاء كوروتين جديد إذا أردت إعادة المحاولة.

local co = coroutine.create(function()
  error("something went wrong")
end)

local ok, err = coroutine.resume(co)
print(ok, err)                      -- false  ...: something went wrong
print(coroutine.status(co))         -- dead

-- Cannot resume dead coroutine:
local ok2, err2 = coroutine.resume(co)
print(ok2, err2)  -- false  cannot resume dead coroutine

coroutine.isyieldable

تعيد coroutine.isyieldable() القيمة true إذا كان الكوروتين قيد التشغيل يستطيع تنفيذ yield. وتعيد القيمة false في الخيط الرئيسي وفي دوال C التي لا تدعم yield. تحقّق دائمًا قبل تنفيذ yield إذا لم تكن متأكدًا من السياق.

local co = coroutine.create(function()
  print("isyieldable:", coroutine.isyieldable())  -- true
  coroutine.yield()
end)

coroutine.resume(co)

-- In main thread:
print("isyieldable:", coroutine.isyieldable())  -- false
-- coroutine.yield()  -- ERROR in main thread

مراقبة مجموعة من الكوروتينات

تتبّع مجموعة من الكوروتينات، وأزل الكوروتينات المنتهية بعد كل جولة من عمليات الاستئناف. وهذا هو الأساس الذي يُبنى عليه مجدول المهام.

local function makeWorker(n, name)
  return coroutine.create(function()
    for i = 1, n do
      print(name, "step", i)
      coroutine.yield()
    end
  end)
end

local workers = {
  makeWorker(2, "fast"),
  makeWorker(4, "slow"),
}

while #workers > 0 do
  local alive = {}
  for _, co in ipairs(workers) do
    coroutine.resume(co)
    if coroutine.status(co) ~= "dead" then
      alive[#alive+1] = co
    end
  end
  workers = alive
end

تصحيح أخطاء الكوروتينات

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

local function namedCo(name, fn)
  local co = coroutine.create(fn)
  return {
    co = co,
    name = name,
    resume = function(self, ...)
      print("[" .. self.name .. "] resume")
      local results = table.pack(coroutine.resume(self.co, ...))
      print("[" .. self.name .. "] status: " .. coroutine.status(self.co))
      return table.unpack(results, 1, results.n)
    end
  }
end

local worker = namedCo("worker1", function()
  coroutine.yield()
end)
worker:resume()
worker:resume()

إعادة تشغيل الكوروتينات المنتهية

بمجرد أن يصبح الكوروتين منتهيًا، لا يمكن استئنافه. ولـ«إعادة تشغيله»، يجب إنشاء كوروتين جديد من الدالة نفسها. ومن الأنماط الشائعة استخدام مصنع ينشئ كوروتين جديدًا عند الطلب.

local function makeCounter(start, step)
  return coroutine.wrap(function()
    local n = start or 0
    while true do
      coroutine.yield(n)
      n = n + (step or 1)
    end
  end)
end

local count = makeCounter(0, 2)
for i = 1, 5 do io.write(count() .. " ") end
print()  -- 0 2 4 6 8

-- "Restart" by creating a new one
count = makeCounter(100)
print(count())   -- 100

سلوك الأخطاء في Coroutine.wrap

عندما يحدث خطأ في كوروتين مغلّف، ينتشر الخطأ خارج استدعاء دالة التغليف. وعلى خلاف coroutine.resume الذي يعيد false+error، ترفع الدوال التي يعيدها wrap الخطأ مباشرةً. استخدم pcall حول استدعاءات wrap إذا كنت بحاجة إلى التقاط الأخطاء.

local gen = coroutine.wrap(function()
  coroutine.yield(1)
  error("oops")
  coroutine.yield(2)  -- never reached
end)

print(gen())   -- 1 (ok)
local ok, err = pcall(gen)
print(ok, err) -- false  ...: oops
-- Subsequent call: dead coroutine
ok, err = pcall(gen)
print(ok, err) -- false  cannot resume dead coroutine

isyieldable مقابل status

هناك طريقتان لفحص سياق الكوروتين: تعطي coroutine.status(co) حالة كوروتين محدد، بينما تخبرك coroutine.isyieldable() بما إذا كان سياق التنفيذ الحالي يستطيع تنفيذ yield. استخدم status للتحقق من الكوروتينات الأخرى، واستخدم isyieldable للتحقق من إمكانية تنفيذ yield بأمان.

local function maybeYield()
  if coroutine.isyieldable() then
    coroutine.yield()
  else
    -- in main thread or non-yieldable context
    print("cannot yield here")
  end
end

maybeYield()  -- prints "cannot yield here" (main thread)

local co = coroutine.create(maybeYield)
coroutine.resume(co)   -- yields successfully

اختبار سريع

ما الحالة التي يدخل فيها الكوروتين عند انتهاء تنفيذ دالة جسمه؟

مراجعة: حالة الكوروتين

الملخص:

  • الحالات: معلّق ← قيد التشغيل ↔ عادي ← منتهٍ
  • يعيد coroutine.status(co) سلسلة الحالة
  • منتهٍ = انتهى التنفيذ أو حدث خطأ؛ ولا يمكن استئنافه
  • يتحقق coroutine.isyieldable() مما إذا كان السياق الحالي يستطيع تنفيذ yield
  • تحقّق دائمًا من الحالة قبل الاستئناف داخل الحلقات
  • تنتشر أخطاء wrap مباشرةً؛ بينما يعيد resume القيمة false+err

الأسئلة الشائعة

هل درس «حالة البرنامج التعاوني» مجاني؟

نعم — نص درس «حالة البرنامج التعاوني» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.

ماذا ستتعلم في «حالة البرنامج التعاوني»؟

تحقّق من حالة البرنامج التعاوني باستخدام coroutine.status: ‏running وsuspended وdead تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟

لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «حالة البرنامج التعاوني»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟

نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. إنشاء البرامج التعاونية
  2. ‏resume وyield
  3. حالة البرنامج التعاوني
  4. نمط المنتج والمستهلك
← العودة إلى Lua Academy