0Pricing
Lua Academy · درس

إنشاء البرامج التعاونية

أنشئ برامج تعاونية باستخدام coroutine.create وcoroutine.wrap

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

ما هي Coroutine؟

‏Coroutine هي دالة يمكنها إيقاف تنفيذها مؤقتًا (yield) ثم استئنافه لاحقًا من الموضع الذي توقفت عنده. وعلى خلاف الخيوط، تعمل Coroutines بأسلوب تعاوني؛ إذ تعمل واحدة فقط في كل مرة، وتتنازل صراحةً عن التحكم. وتمتلك Coroutines في Lua مكدسًا ومتغيرات محلية خاصة بها.

local co = coroutine.create(function()
  print("start")
  coroutine.yield()
  print("resumed")
  coroutine.yield()
  print("done")
end)

print(coroutine.status(co))   -- suspended
coroutine.resume(co)          -- start
print(coroutine.status(co))   -- suspended
coroutine.resume(co)          -- resumed

‏coroutine.create مقابل coroutine.wrap

تنشئ coroutine.create(fn) Coroutine وتعيد كائن Coroutine من النوع thread. أما coroutine.wrap(fn) فتنشئ Coroutine وتعيد دالة يؤدي استدعاؤها إلى استئنافها. تكون wrap أبسط، لكنها تخفي كائن Coroutine.

-- create: returns coroutine object
local co = coroutine.create(function(x)
  return x * 2
end)
local ok, val = coroutine.resume(co, 5)
print(ok, val)   -- true  10

-- wrap: returns a resumable function
local gen = coroutine.wrap(function(x)
  return x * 3
end)
print(gen(5))    -- 15

دورة حياة Coroutine

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

local co = coroutine.create(function()
  coroutine.yield()
end)

print(coroutine.status(co))  -- suspended
coroutine.resume(co)          -- runs until yield
print(coroutine.status(co))  -- suspended again
coroutine.resume(co)          -- runs until end
print(coroutine.status(co))  -- dead

تشغيل عدة Coroutines

أنشئوا عدة Coroutines وشغّلوها بالتناوب من خلال استئناف كل منها بدوره. يحاكي ذلك التنفيذ المتزامن (تعدد المهام التعاوني). وتحافظ كل Coroutine على حالتها بين عمليات yield.

local function worker(name, steps)
  for i = 1, steps do
    print(name .. ": step " .. i)
    coroutine.yield()
  end
end

local co1 = coroutine.create(function() worker("A", 3) end)
local co2 = coroutine.create(function() worker("B", 3) end)

for _ = 1, 3 do
  coroutine.resume(co1)
  coroutine.resume(co2)
end
-- A:1, B:1, A:2, B:2, A:3, B:3

التكرار باستخدام coroutine.wrap

يُستخدم coroutine.wrap عادةً لإنشاء مكررات. وتُستدعى الدالة المُعادة في كل مرة يتقدم فيها المكرر. وعندما ينتهي جسم Coroutine، ترفع الدالة خطأً؛ لذا استخدموا pcall أو تحقّقوا من الحالة عند الحاجة.

local function range(n)
  return coroutine.wrap(function()
    for i = 1, n do
      coroutine.yield(i)
    end
  end)
end

for v in range(5) do
  io.write(v .. " ")
end
print()  -- 1 2 3 4 5

الأخطاء في Coroutines

إذا رفعت Coroutine خطأً، يعيد coroutine.resume القيمة false متبوعة برسالة الخطأ. وتنتقل Coroutine إلى الحالة dead. ولا يمكن استئناف Coroutine منتهية مرة أخرى.

local co = coroutine.create(function(x)
  if x < 0 then error("negative input: " .. x) end
  return math.sqrt(x)
end)

local ok, val = coroutine.resume(co, -1)
print(ok, val)    -- false  input:2: negative input: -1
print(coroutine.status(co))  -- dead

-- Can't resume a dead coroutine:
ok, val = coroutine.resume(co)
print(ok, val)    -- false  cannot resume dead coroutine

هوية Coroutine

يعيد coroutine.running() الـCoroutine قيد التشغيل حاليًا، وقيمة منطقية تشير إلى ما إذا كانت هي الخيط الرئيسي. استخدموا ذلك داخل Coroutine للحصول على مرجع إليها.

local co = coroutine.create(function()
  local self, isMain = coroutine.running()
  print("type:", type(self))      -- thread
  print("isMain:", isMain)        -- false
  print("status:", coroutine.status(self)) -- running
end)

coroutine.resume(co)

-- In main thread:
local main, isMain = coroutine.running()
print("main isMain:", isMain)    -- true

مولّد لا نهائي

يمكن أن يحتوي جسم Coroutine على حلقة لا نهائية تتخللها عمليات yield؛ وبذلك ينتج المولّد القيم عند الطلب دون أن ينتهي. وهذه حالة استخدام أساسية: تسلسلات كسولة ولا نهائية.

local function naturals(start)
  return coroutine.wrap(function()
    local n = start or 1
    while true do
      coroutine.yield(n)
      n = n + 1
    end
  end)
end

local gen = naturals(1)
for i = 1, 8 do
  io.write(gen() .. " ")
end
print()  -- 1 2 3 4 5 6 7 8

استخدام Coroutines باعتبارها مهامًا

من أمثلة جدولة المهام الأساسية تخزين Coroutines في قائمة انتظار واستئناف كل منها بدوره. عند تنفيذ Coroutine لعملية yield، تعود إلى قائمة الانتظار. وعند انتهائها، تُزال منها. هذا مجدول تعاوني بسيط.

local tasks = {}

local function spawn(fn)
  tasks[#tasks+1] = coroutine.create(fn)
end

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

spawn(function() for i=1,3 do print("T1:"..i); coroutine.yield() end end)
spawn(function() for i=1,3 do print("T2:"..i); coroutine.yield() end end)
run()

ذاكرة الكوروتين

يمتلك كل كوروتين مكدسًا خاصًا به. وقد تكبر المكدسات عند وجود سلاسل استدعاءات عميقة. في سيناريوهات الأداء العالي، تجنّب إنشاء آلاف الكوروتينات النشطة في الوقت نفسه. أعد استخدام الكوروتينات متى أمكن، أو استخدم التجميعات.

-- Coroutine pool concept
local pool = {}

local function getCoroutine(fn)
  -- Reuse dead coroutine slots
  for i, co in ipairs(pool) do
    if coroutine.status(co) == "dead" then
      pool[i] = coroutine.create(fn)
      return pool[i]
    end
  end
  local co = coroutine.create(fn)
  pool[#pool+1] = co
  return co
end

print("Pool pattern for coroutine reuse")

اختبار سريع

ما الحالة التي يكون فيها الكوروتين مباشرةً بعد coroutine.create(fn)؟

مراجعة: إنشاء الكوروتينات

الملخص:

  • coroutine.create(fn) ← كائن كوروتين؛ wrap(fn) ← دالة قابلة للاستئناف
  • الحالات: معلّق ← قيد التشغيل ← معلّق/منتهٍ
  • تبدأ العملية أو تُستأنف باستخدام coroutine.resume(co, ...)
  • الأخطاء أثناء الاستئناف: false + رسالة الخطأ؛ وينتقل الكوروتين إلى الحالة المنتهية
  • مولدات لا نهائية باستخدام while true do yield() end
  • تُستخدم لتعدد المهام التعاوني والتسلسلات الكسولة

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

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

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

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

أنشئ برامج تعاونية باستخدام coroutine.create وcoroutine.wrap تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

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

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

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

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

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

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

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

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