Lua - сопрограммы

Введение

Сопрограммы по своей природе являются совместными, что позволяет выполнять два или более методов контролируемым образом. С сопрограммами в любой момент времени выполняется только одна сопрограмма, и эта работающая сопрограмма приостанавливает свое выполнение только тогда, когда она явно запрашивает приостановку.

Приведенное выше определение может показаться расплывчатым. Предположим, у нас есть два метода: метод основной программы и сопрограмма. Когда мы вызываем сопрограмму с помощью функции возобновления, она начинает выполнение, а когда мы вызываем функцию yield, она приостанавливает выполнение. И снова та же сопрограмма может продолжить выполнение с другим вызовом функции возобновления, с которой она была приостановлена. Этот процесс может продолжаться до конца выполнения сопрограммы.

Функции, доступные в сопрограммах

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

Sr. No. Метод и цель
1

coroutine.create (f)

Создает новую сопрограмму с функцией f и возвращает объект типа «поток».

2

coroutine.resume (co [, val1, ...])

Возобновляет сопрограмму co и передает параметры, если таковые имеются. Он возвращает статус операции и необязательные другие возвращаемые значения.

3

coroutine.running ()

Возвращает запущенную сопрограмму или nil, если вызывается в основном потоке.

4

coroutine.status (co)

Возвращает одно из значений из запущенного, нормального, приостановленного или мертвого в зависимости от состояния сопрограммы.

5

coroutine.wrap (f)

Как и coroutine.create, функция coroutine.wrap также создает сопрограмму, но вместо того, чтобы возвращать саму сопрограмму, она возвращает функцию, которая при вызове возобновляет сопрограмму.

6

coroutine.yield (...)

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

пример

Давайте посмотрим на пример, чтобы понять концепцию сопрограмм.

co = coroutine.create(function (value1,value2)
   local tempvar3 = 10
   print("coroutine section 1", value1, value2, tempvar3)
	
   local tempvar1 = coroutine.yield(value1+1,value2+1)
   tempvar3 = tempvar3 + value1
   print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
	
   local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
   tempvar3 = tempvar3 + value1
   print("coroutine section 3",tempvar1,tempvar2, tempvar3)
   return value2, "end"
	
end)

print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))

Когда мы запустим вышеуказанную программу, мы получим следующий результат.

coroutine section 1	3	2	10
main	true	4	3
coroutine section 2	12	nil	13
main	true	5	1
coroutine section 3	5	6	16
main	true	2	end
main	false	cannot resume dead coroutine

Что делает приведенный выше пример?

Как упоминалось ранее, мы используем функцию возобновления, чтобы запустить операцию, и функцию yield, чтобы остановить операцию. Кроме того, вы можете видеть, что функция возобновления сопрограммы получает несколько возвращаемых значений.

  • Сначала мы создаем сопрограмму и назначаем ее переменной с именем co, а сопрограмма принимает две переменные в качестве своих параметров.

  • Когда мы вызываем первую функцию возобновления, значения 3 и 2 сохраняются во временных переменных value1 и value2 до конца сопрограммы.

  • Чтобы вы это поняли, мы использовали tempvar3, которая изначально равна 10, и она обновляется до 13 и 16 при последующих вызовах сопрограмм, поскольку значение1 сохраняется как 3 на протяжении всего выполнения сопрограммы.

  • Первый coroutine.yield возвращает два значения 4 и 3 функции возобновления, которые мы получаем, обновляя входные параметры 3 и 2 в операторе yield. Он также получает статус выполнения сопрограммы истина / ложь.

  • Еще одна особенность сопрограмм - это то, как заботятся о следующих параметрах вызова возобновления в приведенном выше примере; вы можете видеть, что переменная coroutine.yield получает следующие параметры вызова, что обеспечивает мощный способ выполнения новой операции с сохранением существующих значений параметров.

  • Наконец, как только все операторы в сопрограммах будут выполнены, последующие вызовы вернутся в false и в качестве ответа оператор «не может возобновить мертвую сопрограмму».

Другой пример сопрограммы

Давайте посмотрим на простую сопрограмму, которая возвращает число от 1 до 5 с помощью функции yield и функции возобновления. Он создает сопрограмму, если она недоступна, или возобновляет существующую сопрограмму.

function getNumber()
   local function getNumberHelper()
      co = coroutine.create(function ()
      coroutine.yield(1)
      coroutine.yield(2)
      coroutine.yield(3)
      coroutine.yield(4)
      coroutine.yield(5)
      end)
      return co
   end
	
   if(numberHelper) then
      status, number = coroutine.resume(numberHelper);
		
      if coroutine.status(numberHelper) == "dead" then
         numberHelper = getNumberHelper()
         status, number = coroutine.resume(numberHelper);
      end
		
      return number
   else
      numberHelper = getNumberHelper()
      status, number = coroutine.resume(numberHelper);
      return number
   end
	
end

for index = 1, 10 do
   print(index, getNumber())
end

Когда мы запустим вышеуказанную программу, мы получим следующий результат.

1	1
2	2
3	3
4	4
5	5
6	1
7	2
8	3
9	4
10	5

Часто сопрограммы сравнивают с потоками языков мультипрограммирования, но мы должны понимать, что сопрограммы имеют схожие функции потоков, но они выполняются только по одному за раз и никогда не выполняются одновременно.

Мы контролируем последовательность выполнения программы для удовлетворения потребностей с предоставлением временного сохранения определенной информации. Использование глобальных переменных с сопрограммами обеспечивает еще большую гибкость сопрограмм.