Поиск…


Синтаксис

  • coroutine.create (function) возвращает сопрограмму (type (coroutine) == 'thread'), содержащую эту функцию.

  • coroutine.resume (co, ...) возобновить или запустить сопрограмму. Любые дополнительные аргументы, возвращаемые резюме, возвращаются из coroutine.yield (), которые ранее приостановили сопрограмму. Если сопрограмма не была запущена, дополнительные аргументы становятся аргументами функции.

  • coroutine.yield (...) дает текущую исполняемую копию. Выполнение выполняет резервное копирование после вызова coroutine.resume (), который начал эту сопрограмму. Любые аргументы, даваемые уроку, возвращаются из соответствующей сопрограммы coroutine.resume (), которая запускает сопрограмму.

  • coroutine.status (co) возвращает статус сопрограммы, которая может быть:

    • «dead»: функция в сопрограмме дошла до конца, и сопрограмма не может быть возобновлена ​​больше
    • «running»: сопрограмма продолжена и работает
    • «normal»: сопрограмма возобновила другую сопрограмму
    • «приостановлено»: сопротекция уступила и ждет возобновления
  • Функция coroutine.wrap (function) возвращает функцию, которая при вызове возобновляет сопрограмму, которая была бы создана командой coroutine.create (function).

замечания

Система coroutine была реализована в lua для эмуляции многопоточности, существующей на других языках. Он работает, переключаясь с чрезвычайно высокой скоростью между различными функциями, чтобы пользователь-пользователь считал, что они выполняются одновременно.

Создание и использование сопрограммы

Все функции для взаимодействия с сопрограммами доступны в таблице сопрограмм . Новая сопрограмма создается с помощью функции coroutine.create с единственным аргументом: функция с исполняемым кодом:

thread1 = coroutine.create(function()
            print("honk")
        end)

print(thread1)
-->> thread: 6b028b8c

Объект coroutine возвращает значение типа thread , представляющего новую сопрограмму. Когда создается новая сопрограмма, ее начальное состояние приостанавливается:

print(coroutine.status(thread1))
-->> suspended

Чтобы возобновить или запустить сопрограмму, используется функция coroutine.resume , первый аргумент - объект потока:

coroutine.resume(thread1)
-->> honk

Теперь сопрограмма выполняет код и завершается, меняя свое состояние на мертвое , которое невозможно возобновить.

print(coroutine.status(thread1))
-->> dead

Coroutines может приостановить его выполнение и возобновить его позже благодаря функции coroutine.yield :

thread2 = coroutine.create(function()
        for n = 1, 5 do
            print("honk "..n)
            coroutine.yield()
        end
    end)

Как вы можете видеть, coroutine.yield () присутствует внутри цикла for, теперь, когда мы возобновляем сопрограмму coroutine, он будет выполнять код, пока не достигнет coroutine.yield:

coroutine.resume(thread2)
-->> honk 1
coroutine.resume(thread2)
-->> honk 2

По завершении цикла состояние потока становится мертвым и не может быть возобновлено. Coroutines также позволяет обмен данными:

thread3 = coroutine.create(function(complement)
    print("honk "..complement)
    coroutine.yield()
    print("honk again "..complement)
end)
coroutine.resume(thread3, "stackoverflow")
-->> honk stackoverflow

Если сопрограмма выполняется снова без дополнительных аргументов, дополнение будет по-прежнему аргументом из первого резюме, в данном случае «stackoverflow»:

coroutine.resume(thread3)
-->> honk again stackoverflow

Наконец, когда coroutine заканчивается, любые значения, возвращаемые его функцией, переходят к соответствующему резюме:

thread4 = coroutine.create(function(a, b)
    local c = a+b
    coroutine.yield()
    return c
end)
coroutine.resume(thread4, 1, 2)
print(coroutine.resume(thread4))
-->> true, 3

В этой функции используются Coroutines для передачи значений обратно в вызывающий поток из глубины рекурсивного вызова.

local function Combinations(l, r)
    local ll = #l
    r = r or ll
    local sel = {}
    local function rhelper(depth, last)
        depth = depth or 1
        last = last or 1
        if depth > r then
            coroutine.yield(sel)
        else
            for i = last, ll - (r - depth) do
                sel[depth] = l[i]
                rhelper(depth+1, i+1)
            end
        end
    end
    return coroutine.wrap(rhelper)
end

for v in Combinations({1, 2, 3}, 2) do
    print("{"..table.concat(v, ", ").."}")
end
--> {1, 2}
--> {1, 3}
--> {2, 3}

Coroutines также может использоваться для ленивой оценки.

-- slices a generator 'c' taking every 'step'th output from the generator
-- starting at the 'start'th output to the 'stop'th output
function slice(c, start, step, stop)
    local _
    return coroutine.wrap(function()
        for i = 1, start-1 do
            _ = c()
        end
        for i = start, stop do
            if (i - start) % step == 0 then
                coroutine.yield(c())
            else
                _ = c()
            end
        end
    end)
end


local alphabet = {}
for c = string.byte('a'), string.byte('z') do
    alphabet[#alphabet+1] = string.char(c)
end
-- only yields combinations 100 through 102
-- requires evaluating the first 100 combinations, but not the next 5311633
local s = slice(Combinations(alphabet, 10), 100, 1, 102)
for i in s do
    print(table.concat(i))
end
--> abcdefghpr
--> abcdefghps
--> abcdefghpt

Coroutines можно использовать для конструкций трубопроводов, как описано в « Программирование в Lua» . Автор PIL, Роберто Иерусульсамчий, также опубликовал статью об использовании сопрограмм для внедрения более совершенной и общей механики управления потоком, например продолжения.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow