English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Lua координаты (coroutine) очень похожи на потоки: имеют независимый стек, независимые локальные переменные, независимый указатель команды, и в то же время совместно используют глобальные переменные и многое другое с другими координатами.
Координаты - это очень мощная функция, но также и сложная в использовании.
Основное различие между потоками и координатами заключается в том, что программа с несколькими потоками может одновременно запускать несколько потоков, в то время как координаты должны работать друг с другом.
В каждый момент времени выполняется только одна координата, и координата, выполняющаяся, приостанавливается только по требованию.
Координаты несколько напоминают синхронизированные многопоточность, несколько потоков, ожидающих одного и того же mutex, напоминают координаты.
Метод | Описание |
---|---|
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() | возвращает运行的 coroutine, coroutine - это поток, при использовании running возвращает номер потока coroutine |
-- coroutine_test.lua файл 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 ----------
function running можно увидеть, что coroutine в底层 реализована как поток
при создании coroutine в новом потоке регистрируется событие
при использовании resume для инициирования события функция coroutine.create выполняется, при встрече с yield текущий поток приостанавливается, ожидая повторного инициирования события resume
далее мы анализируем более детальный пример:
function foo(a) print("foo функция вывод", a) return coroutine.yield(2 * a) -- возвращает значение 2*a end co = coroutine.create(function (a , b)} print("Первый раз выполнение协同 program выводит", a, b) -- co-body 1 10 local r = foo(a + 1) print("Второй раз выполнение协同 program выводит", r) local r, s = coroutine.yield(a + b, a - b) -- а, b являются значениями,传入 при первом вызове协同 program print("Третий раз выполнение协同 program выводит", r, s) return b, "окончить协同 program" -- значение b является значением,传入 при втором вызове协同 program 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 end print("---Разделительная линия---") print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine print("---Разделительная линия---")
Результат выполнения примера выше:
Первый раз выполнение协同 program выводит 1 10 вывод функции foo 2 main true 4 --Разделительная линия---- Второй раз выполнение协同 program выводит r main true 11 -9 ---Разделительная линия--- Третий раз выполнение协同 program выводит x y main true 10 окончить协同 program ---Разделительная линия--- main false cannot resume dead coroutine ---Разделительная линия---
Пример продолжается следующим образом:
Вызов resume, чтобы唤醒协同程序, операция resume успешна и возвращает true,否则 возвращает false;
协同程序运行;
Доходят до строки yield;
yield приостанавливает协同程序, первый resume возвращает;( 注意:此处 yield 返回, параметр является параметром resume)
Второй раз唤醒协同程序;( 注意:此处 resume 参数中,除了第一个参数,其余参数将作为 yield 参数)
return;
Синхронизация продолжается;
Если используемый协同program продолжает работать и вызывается resume метод после завершения, выводится: cannot resume dead coroutine
Сила сочетания resume и yield заключается в том, что resume находится в основном коде, он传入 внешние состояния (данные) в协同program; а yield возвращает внутренние состояния (данные) в основной код.
Теперь я использую协同program 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 ……