0Pricing
Lua Academy · درس

‏resume وyield

تبادل البيانات بين المستدعي والبرنامج التعاوني باستخدام resume/yield

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

تمرير القيم إلى الكوروتين

تصبح الوسائط الممررة إلى أول استدعاء لـ coroutine.resume معاملات دالة جسم الكوروتين. أما الوسائط الممررة إلى عمليات الاستئناف اللاحقة، فتعيدها استدعاءة coroutine.yield() التي أوقفت الكوروتين.

local co = coroutine.create(function(a, b)
  print("received:", a, b)        -- 10  20
  local c = coroutine.yield()     -- pauses
  print("after yield:", c)        -- 30
end)

coroutine.resume(co, 10, 20)  -- first call: passes a,b
coroutine.resume(co, 30)      -- subsequent: passed to yield

القيم من yield

تصبح القيم الممررة إلى coroutine.yield(val1, val2) قيم الإرجاع لاستدعاء coroutine.resume() الذي توقّف عند yield. لذلك يمكن القول إن yield «يعيد» القيم إلى المستدعي.

local co = coroutine.create(function()
  coroutine.yield(1, "hello")
  coroutine.yield(2, "world")
  return 3, "done"
end)

local ok, a, b = coroutine.resume(co)
print(ok, a, b)   -- true  1  hello

ok, a, b = coroutine.resume(co)
print(ok, a, b)   -- true  2  world

ok, a, b = coroutine.resume(co)
print(ok, a, b)   -- true  3  done

الاتصال ثنائي الاتجاه

تتيح الكوروتينات اتصالًا ثنائي الاتجاه فعليًا: يمرر المستدعي البيانات عبر resume، ويعالجها الكوروتين ثم يعيد النتائج عبر yield. كل عملية resume/yield هي تبادل متزامن.

local co = coroutine.create(function(x)
  while true do
    x = coroutine.yield(x * x)  -- yield x^2, get next x
  end
end)

coroutine.resume(co)  -- start (x=nil initially)
local ok, sq
ok, sq = coroutine.resume(co, 3); print(sq)  -- 9
ok, sq = coroutine.resume(co, 5); print(sq)  -- 25
ok, sq = coroutine.resume(co, 7); print(sq)  -- 49

المنتج والمستهلك

النمط الكلاسيكي للكوروتينات: ينتج المنتج العناصر واحدًا تلو الآخر باستخدام yield، ويستأنف المستهلك المنتج كلما احتاج إلى العنصر التالي. لا يتقدم أي منهما على الآخر — وهذا يحقق تزامنًا مثاليًا.

local function producer(items)
  return coroutine.create(function()
    for _, item in ipairs(items) do
      coroutine.yield(item)
    end
  end)
end

local pro = producer({"apple","banana","cherry"})

-- Consumer drives the loop
while true do
  local ok, item = coroutine.resume(pro)
  if not ok or item == nil then break end
  print("consumed:", item)
end

خط أنابيب باستخدام الكوروتينات

يمكن ربط عدة كوروتينات لتكوين خط أنابيب. تقرأ كل مرحلة من المرحلة السابقة وتُمرر النتائج إلى المرحلة التالية باستخدام yield. وتقود المرحلة النهائية خط الأنابيب باستئناف المرحلة الأخيرة، مما يؤدي إلى انتقال الاستئناف عبر السلسلة بأكملها.

local function source(items)
  return coroutine.wrap(function()
    for _, v in ipairs(items) do coroutine.yield(v) end
  end)
end

local function filter(iter, pred)
  return coroutine.wrap(function()
    for v in iter do
      if pred(v) then coroutine.yield(v) end
    end
  end)
end

local function map(iter, fn)
  return coroutine.wrap(function()
    for v in iter do coroutine.yield(fn(v)) end
  end)
end

local pipeline = map(filter(source({1,2,3,4,5,6}),
  function(n) return n%2==0 end),
  function(n) return n*n end)

for v in pipeline do io.write(v.." ") end
print()  -- 4 16 36

الكوروتينات لمحاكاة العمليات غير المتزامنة

من دون خيوط نظام التشغيل، يمكن للكوروتينات محاكاة العمليات غير المتزامنة: استخدم yield أثناء «الانتظار»، ثم استأنف الكوروتين عندما تصبح «النتيجة» جاهزة. ويستأنف المجدول الكوروتين مع تمرير النتيجة إليه.

local scheduler = {}
local current = nil

local function await(key)
  coroutine.yield(key)  -- tell scheduler what we need
  return coroutine.yield()  -- wait for result
end

local co = coroutine.create(function()
  local data = await("fetch:users")
  print("Got users:", data)
end)

-- Start coroutine
local ok, want = coroutine.resume(co)
print("Coroutine wants:", want)  -- fetch:users
-- Simulate delivering the result:
coroutine.resume(co, {{name="Alice"},{name="Bob"}})

yield داخل دالة

يمكنك استخدام yield داخل أي دالة يستدعيها كوروتين، وليس فقط داخل الدالة ذات المستوى الأعلى. ينتقل yield صعودًا عبر جميع الاستدعاءات المتداخلة حتى يعود إلى resume. ويُسمى ذلك «مكدس استدعاءات معلّقًا».

local function yieldTwice(label)
  coroutine.yield(label .. ":1")
  coroutine.yield(label .. ":2")
end

local co = coroutine.create(function()
  yieldTwice("A")
  yieldTwice("B")
end)

for i = 1, 4 do
  local ok, v = coroutine.resume(co)
  print(v)
end
-- A:1, A:2, B:1, B:2

الكوروتينات ليست خيوطًا

كوروتينات Lua ليست خيوطًا لنظام التشغيل. يعمل كوروتين واحد فقط في كل مرة؛ ولا توجد جدولة استباقية أو توازٍ. تشترك جميع الكوروتينات في خيط واحد لنظام التشغيل. ولتحقيق التوازي الفعلي، تحتاج إلى حالات Lua متعددة في خيوط منفصلة لنظام التشغيل.

-- This is NOT parallel - interleaved execution
local function task(name, n)
  for i = 1, n do
    print(name, i)
    coroutine.yield()
  end
end

local t1 = coroutine.create(function() task("A", 3) end)
local t2 = coroutine.create(function() task("B", 3) end)

-- Must explicitly schedule:
for _ = 1, 3 do
  coroutine.resume(t1)
  coroutine.resume(t2)
end
-- A1, B1, A2, B2, A3, B3 (interleaved, NOT parallel)

الحالة بعد الاستئناف

تحقق من حالة الكوروتين لتقرر ما إذا كان ينبغي استئنافه مرة أخرى. يكون الكوروتين الذي انتهى (بعد عودته من جسمه) في حالة «منتهٍ» — ويؤدي استئنافه إلى إرجاع false مع خطأ. تحقّق دائمًا من الحالة قبل الاستئناف داخل الحلقات.

local co = coroutine.create(function()
  for i = 1, 3 do coroutine.yield(i) end
end)

while coroutine.status(co) ~= "dead" do
  local ok, val = coroutine.resume(co)
  if ok and val ~= nil then
    print("val:", val)
  end
end
-- val: 1, val: 2, val: 3

عمليات yield متعددة في استئناف واحد

يشغّل استدعاء واحد لـ coroutine.resume الكوروتين حتى يصل إلى yield التالي أو ينتهي. لا يمكنك جعل الكوروتين ينفذ yield عدة مرات أثناء عملية استئناف واحدة؛ إذ يعلّق كل yield التنفيذ وينتظر عملية الاستئناف التالية.

local co = coroutine.create(function()
  local x = coroutine.yield("first")
  print("got:", x)
  local y = coroutine.yield("second")
  print("got:", y)
end)

local _, v1 = coroutine.resume(co)         -- starts, yields "first"
print("yielded:", v1)                       -- first
local _, v2 = coroutine.resume(co, "a")   -- passes "a", yields "second"
print("yielded:", v2)                       -- second
coroutine.resume(co, "b")                   -- passes "b", coroutine ends

اختبار سريع

إلى ماذا تتحول القيم الممررة إلى coroutine.yield(v1, v2)؟

مراجعة: resume وyield

الملخص:

  • وسائط أول عملية resume ← معاملات جسم الكوروتين
  • وسائط عمليات resume اللاحقة ← القيم التي يعيدها yield() السابق
  • وسائط yield ← القيم التي يعيدها resume() الذي أدى إلى تنفيذ yield
  • اتصال ثنائي الاتجاه: كل resume/yield يمثل تبادلًا
  • يعمل yield من داخل أي دالة متداخلة
  • الكوروتينات تعاونية وليست متوازية

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

هل درس «‏resume وyield» مجاني؟

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

ماذا ستتعلم في «‏resume وyield»؟

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

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

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

كم من الوقت يستغرق درس «‏resume وyield»؟

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

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

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

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

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