English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Lua Coroutine(التعاونية)

ما هو المعاونة (coroutine)؟

المعاونة Lua (coroutine) تشبه إلى حد كبير السينكروني:تملك ذاكرة مستقلة،متغيرات محلية مستقلة،مؤشر أوامر مستقل،وتشارك مع协同 أخرى في متغيرات عالمية وغيرها من الأشياء

المعاونة هي ميزة قوية جدًا،لكنها معقدة جدًا أيضًا في الاستخدام

الفرق بين السينكروني والمعاونة

الفرق الرئيسي بين السينكروني والمعاونة هو أن برنامجًا يحتوي على عدة سينكروني يمكنه تشغيل عدة سينكروني في نفس الوقت،بينما المعاونة تحتاج إلى التشغيل التكافلي

في أي لحظة معينة،يُشغل فقط协同程序 واحد،والمعاونة التي تشغلها تُستدعى إلى الاستقالة بشكل واضح

المعاونة تشبه إلى حد كبير السينكروني المتبادل بين عدد من السينكروني في نفس الخيط،وفي نفس الوقت تشبه المعاونة.

القواعد الأساسية

الطريقةوصف
coroutine.create()إنشاء coroutine،يعود ب coroutine،الم参数 هو فункциة،عندما تستخدم مع resume،تُستيقظ دعوة الفункциة
coroutine.resume()إعادة تشغيل coroutine،استخدامها مع create
coroutine.yield()إيقاف coroutine،تضبط coroutine في حالة الاستقالة،ويمكن استخدامها مع resume للحصول على تأثيرات مفيدة
coroutine.status()مراجعة حالة coroutine
ملاحظة:للمعرفة الوقت الذي يكون فيه حالة coroutine واحدة من هذه الحالات: dead،suspended،running،يرجى الرجوع إلى البرنامج أدناه
coroutine.wrap()إنشاء coroutine،يعود بفункциة،إذا قمت بتشغيل هذه الفункциة،ستدخل coroutine،ويعاد فيها استخدام ميزة create
coroutine.running()Returns the running coroutine, a coroutine is a thread, when using running, it returns the thread number of a coroutine

The following examples demonstrate the usage of the above methods:

-- coroutine_test.lua file
co = coroutine.create(
    function(i)
        print(i);
    end
)
 
coroutine.resume(co, 1) -- 1
print(coroutine.status(co)) -- dead
 
print("----------")
 
co = coroutine.wrap(
    function(i)
        print(i);
    end
)
 
co(1)
 
print("----------")
 
co2 = coroutine.create(
    function()
        for i = 1, 10 do
            print(i)
            if i == 3 then
                print(coroutine.status(co2)) -- running
                print(coroutine.running()) -- thread:XXXXXX
            end
            coroutine.yield()
        end
    end
)
 
coroutine.resume(co2) -- 1
coroutine.resume(co2) -- 2
coroutine.resume(co2) -- 3
 
print(coroutine.status(co2)) -- suspended
print(coroutine.running())
 
print("----------")

نتائج تنفيذ الأمثلة أعلاه هي:

1
dead
----------
1
----------
1
2
3
running
thread: 0x7fb801c05868          false
suspended
thread: 0x7fb801c04c88          true
----------

From coroutine.running, it can be seen that coroutine is implemented as a thread at the bottom level.

When creating a coroutine, it is equivalent to registering an event in a new thread.

When using resume to trigger an event, the coroutine function created by create is executed, and when encountering yield, it represents pausing the current thread and waiting for the next resume to trigger the event.

Next, we analyze a more detailed example:

function foo(a)
    print("foo function output", a)
    return coroutine.yield(2 * a) -- returns the value of 2*a
end
 
co = coroutine.create(function (a , b)}
    print("إخراج تنفيذ البرنامج المتعاوني الأول", a, b) -- co-body 1 10
    local r = foo(a + 1)
     
    print("إخراج تنفيذ البرنامج المتعاوني الثاني", r)
    local r, s = coroutine.yield(a + b, a - b) -- قيم a،b هي التي تم تمريرها عند الدعوة الأولى للبرنامج المتعاوني
     
    print("إخراج تنفيذ البرنامج المتعاوني الثالثة", r, s)
    return b, "إنهاء برنامج التعاون"                   -- قيمة b هي التي تم تمريرها عند الدعوة الثانية للبرنامج المتعاوني
end)
        
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--خط فاصل----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---خط فاصل---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 انتهاء
print("---خط فاصل---")
print("main", coroutine.resume(co, "x", "y")) -- لا يمكن استيقاظ البرنامج المتوقف
print("---خط فاصل---")

نتائج تنفيذ الأمثلة أعلاه هي:

إخراج تنفيذ البرنامج المتعاوني الأول    1    10
إخراج foo الوظيفة    2
main    true    4
--خط فاصل----
إخراج تنفيذ البرنامج المتعاوني الثاني    r
main    true    11    -9
---خط فاصل---
إخراج تنفيذ البرنامج المتعاوني الثالثة    x    y
main    true    10    إنهاء برنامج التعاون
---خط فاصل---
main    false    لا يمكن استيقاظ البرنامج المتوقف
---خط فاصل---

المثال السابق يستمر كما يلي:

  • دعوة resume لاستيقاظ برنامج التعاون، العودة بنجاح لـ resume هي true، وإلا false؛

  • تنفيذ برنامج التعاون;

  • التنفيذ حتى جملة yield;

  • إيقاف برنامج التعاون باستخدام yield، والعودة الأولى باستخدام resume;(ملاحظة: هنا، العودة باستخدام yield هي معلمات resume)

  • الاستيقاظ الثاني لبرنامج التعاون؛(ملاحظة: 参数 resume باستثناء الأولي، سيتم استخدام الباقي كمعلمات yield)

  • استمرار yield في العودة;

  • استمرار التعاونية في العمل؛

  • إذا استمرت التعاونية في العمل بعد إكمالها وإعادة التطبيق لأسلوب resume فإن النتيجة ستكون: cannot resume dead coroutine

قوة تعاون resume و yield تكمن في أن resume يتواجد في البرنامج الرئيسي، حيث يدخل الحالة الخارجية (البيانات) إلى التعاونية الداخلية؛ بينما يعيد yield الحالة الداخلية (البيانات) إلى البرنامج الرئيسي.

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

الآن سأستخدم coroutine Lua لحل المشكلة الكلاسيكية لمشكلة المنتج والمستهلك.

local newProductor
function productor()
     local i = 0
     while true do
          i = i + 1
          send(i)     -- إرسال البضاعة المنتجة إلى المستهلك
     end
end
function consumer()
     while true do
          local i = receive()     -- الحصول على البضاعة من المنتج
          print(i)
     end
end
function receive()
     local status, value = coroutine.resume(newProductor)
     return value
end
function send(x)
     coroutine.yield(x)     -- x يشير إلى القيمة التي يجب إرسالها، بعد إرسال القيمة، يتم تعليق التعاونية
end
-- بدء البرنامج
newProductor = coroutine.create(productor)
consumer()

نتائج تنفيذ الأمثلة أعلاه هي:

1
2
3
4
5
6
7
8
9
10
11
12
13
……