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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.