Учебники

Луа — сопрограммы

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

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

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

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

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

coroutine.create (f)

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

2

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

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

3

coroutine.running ()

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

4

coroutine.status (со)

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

5

coroutine.wrap (f)

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

6

coroutine.yield (…)

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

coroutine.create (f)

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

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

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

coroutine.running ()

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

coroutine.status (со)

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

coroutine.wrap (f)

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

coroutine.yield (…)

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

пример

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

Live Demo

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 и оператор «не может возобновить мертвую сопрограмму» в качестве ответа.

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

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

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

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

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

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

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

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

Live Demo

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

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

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