Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

Модуль fiber

Общие сведения

С помощью модуля fiber можно:

  • Создавать, запускать и управлять файберами.
  • Отправлять и получать сообщения между различными процессами (то есть разными подключениями, сессиями или файберами) через каналы.
  • Использовать механизм синхронизации для файберов, аналогичный «переменным условия» и функциям операционной системы, таким как pthread_cond_wait() и pthread_cond_signal().

Указатель

Ниже приведен перечень всех функций и элементов модуля fiber.

Name

Use

Fibers

fiber.create()

Создание и запуск файбера

fiber.new()

Создание файбера без запуска

fiber.self()

Получение объекта файбера

fiber.find()

Получение объекта файбера по ID

fiber.sleep()

Перевод файбера в спящий режим

fiber.yield()

Передача управления

fiber.status()

Получение статуса текущего файбера

fiber.info()

Получение информации обо всех файберах

fiber.top()

Возврат таблицы активных файберов и отображение потребления CPU

fiber.kill()

Отмена файбера

fiber.testcancel()

Проверка того, отменен ли текущий файбер

fiber.set_max_slice()

Установка максимального кванта времени по умолчанию для всех файберов

fiber.set_slice()

Установка кванта времени для выполнения текущего файбера

fiber.extend_slice()

Продление кванта времени для выполнения текущего файбера

fiber.check_slice()

Проверка того, истек ли квант времени для текущего файбера

fiber.time()

Получение системного времени в секундах

fiber.time64()

Получение системного времени в микросекундах

fiber.clock()

Получение монотонного времени в секундах

fiber.clock64()

Получение монотонного времени в микросекундах

Fiber object

fiber_object:id()

Получение ID файбера

fiber_object:name()

Получение имени файбера

fiber_object:name(name)

Задание имени файбера

fiber_object:status()

Получение статуса файбера

fiber_object:cancel()

Отмена файбера

fiber_object.set_max_slice()

Установка максимального кванта времени для файбера

fiber_object.storage

Локальное хранилище внутри файбера

fiber_object:set_joinable()

Разрешение новому файберу присоединиться (join)

fiber_object:join()

Ожидание перехода состояния файбера в 'dead'

Channels

fiber.channel()

Создание канала связи

channel_object:put()

Отправка сообщения через канал

channel_object:close()

Закрытие канала

channel_object:get()

Получение сообщения из канала

channel_object:is_empty()

Проверка того, пуст ли канал

channel_object:count()

Подсчет сообщений в канале

channel_object:is_full()

Проверка того, заполнен ли канал

channel_object:has_readers()

Проверка того, есть ли ожидающие читатели у пустого канала

channel_object:has_writers()

Проверка того, есть ли ожидающие писатели у заполненного канала

channel_object:is_closed()

Проверка того, закрыт ли канал

Example

Полезный пример использования каналов

Condition variables

fiber.cond()

Создание переменной состояния

cond_object:wait()

Перевод файбера в спящий режим до пробуждения другим файбером

cond_object:signal()

Пробуждение одного файбера

cond_object:broadcast()

Пробуждение всех файберов

Example

Полезный пример использования переменных состояния

Файберы

Файбер — это набор инструкций, выполняемых в режиме кооперативной многозадачности. Модуль fiber позволяет создать файбер и связать его с пользовательской функцией, называемой функцией файбера.

Файбер может находиться в одном из следующих состояний: running, suspended, ready или dead. В программе с файберами в любой момент времени выполняется только один из них. Выполняемый файбер приостанавливает свою работу только при явной передаче управления другому файберу, готовому к выполнению.

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

Создание файбера

Чтобы создать файбер, вызовите одну из следующих функций:

  • fiber.create() — создает файбер и немедленно запускает его. Начальное состояние файбера — running.
  • fiber.new() — создает файбер, но не запускает его. Начальное состояние файбера — ready. Такие файберы можно присоединить с помощью функции fiber_object:join() и получить результат, возвращенный функцией файбера.

Передача управления

Передача управления (yield) — это действие в кооперативной среде, при котором управление потоком передается от текущего файбера другому файберу, готовому к выполнению. Модуль fiber предоставляет следующие функции для явной передачи управления другому файберу:

  • fiber.yield() — передает управление планировщику.

  • fiber.sleep() — передает управление планировщику и приостанавливает выполнение на указанное количество секунд.

Отмена файбера

Чтобы отменить файбер, используйте функцию fiber_object.cancel. Также можно вызвать fiber.kill(), чтобы найти файбер по его числовому идентификатору и отменить его.

Ограничение времени выполнения

Если файбер работает слишком долго без передачи управления, можно использовать квант времени файбера (fiber slice) для ограничения времени его выполнения. Параметр compat fiber_slice_default управляет значением по умолчанию для максимального кванта времени файбера.

Существует два типа квантов: предупреждающий и ошибочный.

  • При превышении предупреждающего кванта в журнал записывается предупреждение, например:

    fiber has not yielded for more than 0.500 seconds
  • При превышении ошибочного кванта файбер отменяется, и вызывается ошибка FiberSliceIsExceeded:

FiberSliceIsExceeded: fiber slice is exceeded

Управление передается другому файберу, готовому к выполнению.

Проверка кванта времени выполняется всеми функциями, работающими со спейсами и индексами, такими как index_object.select(), space_object.replace() и так далее. Также можно использовать функцию fiber.check_slice() в коде приложения для проверки, не превышен ли квант для текущего файбера.

Следующие функции переопределяют значение по умолчанию для максимального кванта времени файбера:

  • fiber.set_max_slice(slice) — задает максимальный квант по умолчанию для всех файберов.
  • fiber_object:set_max_slice(slice) — задает максимальный квант для конкретного файбера. Максимальный квант устанавливается при пробуждении файбера. Это может быть первый запуск или пробуждение после fiber.yield().

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

  • fiber.set_slice(slice) — задает квант для текущего выполнения файбера.
  • fiber.extend_slice(slice) — увеличивает квант для текущего выполнения файбера. Учтите, что указанные значения не влияют на выполнение файбера после fiber.yield().

Информация о файберах

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

  • fiber.info — возвращает информацию обо всех файберах.
  • fiber.status() — получает статус текущего файбера. Чтобы получить статус указанного файбера, вызовите fiber_object:status().
  • fiber.top() — показывает все активные файберы и потребление ими CPU.

Сборка мусора

Сборщик мусора собирает недоступные файберы так же, как и все Lua-объекты: сборщик мусора в Lua освобождает память выделенного для файбера пула, сбрасывает все данные файбера и возвращает файбер (который теперь называется каркасом файбера) в пул файберов. Каркас можно использовать повторно при создании другого файбера.

Файбер обладает всеми возможностями Lua корутины (coroutine), и все принципы программирования, применимые к корутинам Lua, применимы и к файберам. Однако в Tarantool внесены улучшения для файберов, и они используются внутри системы. Поэтому, хотя использование корутин возможно и поддерживается, рекомендуется использовать файберы.

Справочник по API

fiber.create(function [, function-arguments])

Создание и запуск файбера. Происходит создание файбера, который незамедлительно начинает работу.

Параметры:

  • function (function) — функция, связываемая с файбером
  • function-arguments — аргументы, передаваемые функции

Возвращает

созданный объект файбера

Тип возвращаемого значения

userdata

Пример:

В примере ниже показано, как создать файбер с помощью fiber.create:

-- app.lua --fiber = require('fiber')function greet(name)    print('Hello, '..name)endgreet_fiber = fiber.create(greet, 'John')print('Fiber already started')

После запуска app.lua должен отобразиться следующий вывод:

$ tarantool app.luaHello, JohnFiber already started

fiber.new(function [, function-arguments])

Создает файбер, но не запускает его. Созданный файбер запускается после того, как создатель файбера (то есть задача, вызывающая fiber.new()) передаст управление. Начальное состояние файбера — ready.

Файберы, созданные с помощью fiber.new, можно присоединить, вызвав функцию fiber_object:join(), и получить результат, возвращенный функцией файбера. Чтобы присоединить файбер, необходимо сделать его присоединяемым с помощью fiber_object:set_joinable().

Параметры:

  • function (function) — функция, связываемая с файбером
  • function-arguments — аргументы, передаваемые функции

Возвращает

созданный объект файбера

Тип возвращаемого значения

userdata

Пример:

В примере ниже показано, как создать файбер с помощью fiber.new:

-- app.lua --fiber = require('fiber')function greet(name)    print('Hello, '..name)endgreet_fiber = fiber.new(greet, 'John')print('Fiber not started yet')

После запуска app.lua должен отобразиться следующий вывод:

$ tarantool app.luaFiber not started yetHello, John

fiber.self()

Возвращает

объект файбера для текущего запланированного файбера.

Тип возвращаемого значения

userdata

Пример:

tarantool> fiber.self()---- status: running  name: interactive  id: 101

fiber.find(id)

Параметры:

  • id (number) — числовой идентификатор файбера.

Возвращает

объект файбера для указанного файбера.

Тип возвращаемого значения

userdata

Пример:

tarantool> fiber.find(101)---- status: running  name: interactive  id: 101

fiber.sleep(time)

Передача управления планировщику и переход в режим ожидания на указанное количество секунд. Только текущий файбер можно перевести в режим ожидания.

Параметры:

  • time (number) — количество секунд ожидания.

Возможные ошибки:

см. Пример ошибки при передаче управления.

Пример:

Приведенная ниже функция increment содержит бесконечный цикл, который увеличивает глобальную переменную counter на 1. Затем текущий файбер переходит в режим ожидания на period секунд. sleep вызывает неявный fiber.yield().

-- app.lua --fiber = require('fiber')counter = 0function increment(period)    while true do        counter = counter + 1        fiber.sleep(period)    endendincrement_fiber = fiber.create(increment, 2)require('console').start()

После запуска скрипта выведите информацию о файбере: ID файбера, его статус и значение счетчика:

tarantool> print('ID: ' .. increment_fiber:id() .. '\nStatus: ' .. increment_fiber:status() .. '\nCounter: ' .. counter)ID: 104Status: suspendedCounter: 8---

Затем отмените файбер и выведите информацию о файбере еще раз. В этот раз статус файбера — dead.

tarantool> increment_fiber:cancel()---tarantool> print('ID: ' .. increment_fiber:id() .. 'nStatus: ' .. increment_fiber:status() .. 'nCounter: ' .. counter)ID: 104 Status: deadCounter: 12---

fiber.yield()

Передача управления планировщику. Работает аналогично fiber.sleep(0).

Возможные ошибки:

см. Пример ошибки при вызове yield.

Пример:

В приведенном ниже примере два файбера связаны с одной и той же функцией. Каждый файбер передает управление после вывода приветствия.

-- app.lua --fiber = require('fiber')function greet()    while true do        print('Enter a name:')        name = io.read()        print('Hello, '..name..'. I am fiber '..fiber.id())        fiber.yield()    endendfor i = 1, 2 do    fiber_object = fiber.create(greet)    fiber_object:cancel()end

Вывод может выглядеть следующим образом:

$ tarantool app.luaEnter a name:JohnHello, John. I am fiber 104Enter a name:JaneHello, Jane. I am fiber 105

fiber.status([fiber_object])

Возвращает статус текущего файбера. Если передан fiber_object, возвращает статус указанного файбера.

Параметры:

  • fiber_object (fiber_object) — (необязательный) объект файбера

Возвращает

статус fiber. Одно из значений: dead, suspended или running.

Тип возвращаемого значения

string

Пример:

tarantool> fiber.status()---- running

fiber.info({[backtrace/bt]})

Возврат информации о всех файберах.

Параметры:

  • backtrace (boolean) — показывать стек вызовов. По умолчанию: true. Установите значение false, чтобы отображать меньше информации (разрешение символов может быть ресурсоемким).
  • bt (boolean) — то же, что и backtrace, но с более низким приоритетом.

Возвращает

количество переключений контекста (csw), стек вызовов, общая память, используемая память, ID файбера (fid), имя файбера. Если включен fiber.top или Tarantool собран с ENABLE_FIBER_TOP, также возвращается процессорное время (time).

Тип возвращаемого значения

table

Описание возвращаемых значений

  • csw – количество переключений контекста.
  • backtrace, bt – стек вызовов каждого файбера, показывающий, где он был создан и какие функции были вызваны.
  • memory:
    • total – общий объем памяти, занимаемый файбером как C-структурой, его стеком и т.д.
    • used – фактический объем памяти, используемый файбером.
  • time – дублирует значение "time" из fiber.top().cpu для каждого файбера. Обратите внимание, что подсчет time ведется, только если активна функция fiber.top().

Пример:

tarantool> fiber.info({ bt = true })---- 101:    csw: 1    backtrace:    - C: '#0  0x5dd130 in lbox_fiber_id+96'    - C: '#1  0x5dd13d in lbox_fiber_stall+13'    - L: stall in =[C] at line -1    - L: (unnamed) in \@builtin/fiber.lua at line 59    - C: '#2  0x66371b in lj_BC_FUNCC+52'    - C: '#3  0x628f28 in lua_pcall+120'    - C: '#4  0x5e22a8 in luaT_call+24'    - C: '#5  0x5dd1a9 in lua_fiber_run_f+89'    - C: '#6  0x45b011 in fiber_cxx_invoke(int (*)(__va_list_tag*), __va_list_tag*)+17'    - C: '#7  0x5ff3c0 in fiber_loop+48'    - C: '#8  0x81ecf4 in coro_init+68'    memory: {total = 516472, used = 0}    time: 0    name: lua    fid: 101  102:    csw: 0    backtrace:    - C: '#0  (nil) in +63'    - C: '#1  (nil) in +63'    memory: {total = 516472, used = 0}    time: 0    name: on_shutdown    fid: 102...

fiber.top()

Отображение всех активных файберов и потребляемых ими ресурсов ЦП.

Возвращает

таблица с двумя записями: cpu и cpu_misses

cpu – это ещё одна таблица, в которой ключами являются строки с ID и именами файберов. Для каждого файбера доступны 3 метрики:

  1. instant (в процентах) — доля времени, в течение которой файбер выполнялся на предыдущей итерации цикла обработки событий.
  2. average (в процентах) — экспоненциальное скользящее среднее значений instant по всем предыдущим итерациям цикла обработки событий.
  3. time (в секундах) — оценка времени ЦП, затраченного каждым файбером на обработку за все время его существования. Запись time также добавляется к выводу информации о файбере с помощью fiber.info() (дублируется запись time из fiber.top().cpu для каждого файбера). Обратите внимание, что подсчет time ведется, только если активна функция fiber.top().

cpu_misses показывает число раз, когда поток TX регистрировал перенос файбера на другое ядро процессора во время последней итерации цикла обработки событий. fiber.top() использует счетчик меток времени для измерения времени выполнения каждого файбера. Однако в разных ядрах могут быть разные значения счетчика, поэтому полагаться на разность показаний счетчика можно только в том случае, если оба измерения были проведены на одном и том же ядре; в противном случае разность показаний может даже быть отрицательной. Когда поток TX переносится на другое ядро процессора, Tarantool просто предполагает, что разность показаний была нулевой для последнего измерения. Это снижает точность вычислений, поэтому чем больше значение cpu_misses, тем ниже точность результатов fiber.top().

Пример:

tarantool> fiber.top()---- cpu:    107/lua: {instant = 30.967324490456, time = 0.351821993, average = 25.582738345233}    104/lua: {instant = 9.6473633128437, time = 0.110869897, average = 7.9693406131877}    101/on_shutdown: {instant = 0, time = 0, average = 0}    103/lua: {instant = 9.8026528631511, time = 0.112641118, average = 18.138387232255}    106/lua: {instant = 20.071174377224, time = 0.226901357, average = 17.077908441831}    102/interactive: {instant = 0, time = 9.6858e-05, average = 0}    105/lua: {instant = 9.2461986412164, time = 0.10657528, average = 7.7068458630827}    1/sched: {instant = 20.265286315108, time = 0.237095335, average = 23.141537169257}  cpu_misses: 0...

Обратите внимание, что по умолчанию новые файберы, созданные с помощью fiber.create, называются 'lua', поэтому лучше задавать им явные имена с помощью fiber_object:name('name').

В выводе fiber.top() есть несколько системных файберов, которые могут быть полезны:

  • sched — это специальный системный файбер. Он планирует задачи для других файберов, если они есть, а также обрабатывает некоторые события libev. Высокие значения instant и average в выводе fiber.top() для него возможны в двух случаях:

    • На экземпляре практически нет нагрузки — тогда выполняется почти только sched, а остальные файберы находятся в состоянии ожидания. Поэтому относительно других файберов нагрузка sched может составлять почти 100%.
    • sched обрабатывает большое количество системных событий. Это не должно вызывать проблем с производительностью.
  • Файберы main обрабатывают запросы, поступающие по сети (iproto-запросы). Таких файберов несколько, и при необходимости создаются новые. При поступлении нового запроса свободный файбер принимает его и выполняет. Запросом может быть типичный select/replace/delete/insert или вызов функции. Например, conn:eval() или conn:call().

fiber.kill(id)

Находит файбер по его числовому идентификатору и отменяет его. Иными словами, fiber.kill() объединяет fiber.find() и fiber_object:cancel().

Параметры:

  • id (number) — идентификатор файбера, который нужно отменить.

Возможные ошибки:

указанный файбер не существует или отмена не разрешена.

Пример:

tarantool> fiber.kill(fiber.id()) -- функция с self может вызвать окончание программы---- error: fiber is cancelled

fiber.testcancel()

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

Пример:

tarantool> fiber.testcancel()---- error: fiber is cancelled

fiber.set_max_slice(slice)

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

Параметры:

  • slice (number/table) — квант времени файбера, который может принимать одно из следующих значений:

  • период времени (в секундах), задающий квант ошибки. Пример: fiber.set_max_slice(3).

  • таблица, задающая кванты предупреждения и ошибки (в секундах). Пример: fiber.set_max_slice({warn = 1.5, err = 3}).

Пример:

В примере ниже показано, как использовать set_max_slice для ограничения кванта времени для всех файберов. fiber.check_slice() вызывается внутри длительной операции, чтобы определить, истёк ли квант времени текущего файбера.

-- app.lua --fiber = require('fiber')clock = require('clock')fiber.set_max_slice({warn = 1.5, err = 3})time = clock.monotonic()function long_operation()    while clock.monotonic() - time < 5 do        fiber.check_slice()        -- Long-running operation ⌛⌛⌛ --    endendlong_operation_fiber = fiber.create(long_operation)

Вывод должен выглядеть следующим образом:

$ tarantool app.luafiber has not yielded for more than 1.500 secondsFiberSliceIsExceeded: fiber slice is exceeded

fiber.set_slice(slice)

Устанавливает квант времени для текущего файбера. Квант времени файбера ограничивает период выполнения файбера без передачи управления.

Параметры:

  • slice (number/table) — квант времени файбера, который может принимать одно из следующих значений:

  • период времени (в секундах), задающий квант ошибки. Пример: fiber.set_slice(3).

  • таблица, задающая кванты предупреждения и ошибки (в секундах). Пример: fiber.set_slice({warn = 1.5, err = 3}).

Пример:

В примере ниже показано, как использовать set_slice для ограничения кванта времени текущего файбера. fiber.check_slice() вызывается внутри длительной операции, чтобы определить, истёк ли квант времени текущего файбера.

-- app.lua --fiber = require('fiber')clock = require('clock')time = clock.monotonic()function long_operation()    fiber.set_slice({warn = 1.5, err = 3})    while clock.monotonic() - time < 5 do        fiber.check_slice()        -- Long-running operation ⌛⌛⌛ --    endendlong_operation_fiber = fiber.create(long_operation)

Вывод должен выглядеть следующим образом.

$ tarantool app.luafiber has not yielded for more than 1.500 secondsFiberSliceIsExceeded: fiber slice is exceeded

fiber.extend_slice(slice)

Продлевает квант времени для текущего файбера. Например, если максимальный квант ошибки по умолчанию установлен с помощью fiber.set_max_slice() в значение 3 секунды, extend_slice(1) продлевает квант ошибки до 4 секунд.

Параметры:

  • slice (number/table) — квант времени файбера, который может принимать одно из следующих значений:

  • период времени (в секундах), задающий квант ошибки. Пример: fiber.extend_slice(1).

  • таблица, задающая кванты предупреждения и ошибки (в секундах). Пример: fiber.extend_slice({warn = 0.5, err = 1}).

Пример:

В примере ниже показано, как использовать extend_slice для продления кванта времени текущего файбера. Максимальный квант времени по умолчанию устанавливается с помощью set_max_slice.

-- app.lua --fiber = require('fiber')clock = require('clock')fiber.set_max_slice({warn = 1.5, err = 3})time = clock.monotonic()function long_operation()    fiber.extend_slice({warn = 0.5, err = 1})    while clock.monotonic() - time < 5 do        fiber.check_slice()        -- Long-running operation ⌛⌛⌛ --    endendlong_operation_fiber = fiber.create(long_operation)

Вывод должен выглядеть следующим образом.

$ tarantool app.luafiber has not yielded for more than 2.000 secondsFiberSliceIsExceeded: fiber slice is exceeded

FiberSliceIsExceeded возникает через 4 секунды.

fiber.check_slice()

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

Пример:

См. примеры для следующих функций:

fiber.time()

Возвращает

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

Тип возвращаемого значения

number

Пример:

tarantool> fiber.time(), fiber.time()---- 1448466279.2415- 1448466279.2415

fiber.time64()

Возвращает

текущее системное время (в микросекундах с начала эпохи) в виде 64-битного целого числа. Время берется из часов цикла обработки событий.

Тип возвращаемого значения

cdata (ctype<int64_t>)

Пример:

tarantool> fiber.time(), fiber.time64()---- 1448466351.2708- 1448466351270762

fiber.clock()

Получение монотонного времени в секундах. Для вычисления времени ожидания лучше использовать fiber.clock(), поскольку fiber.time() сообщает системное время, а оно может меняться при изменениях в системе.

Возвращает

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

Тип возвращаемого значения

number

Пример:

tarantool> start = fiber.clock()---tarantool> print(start)248700.58805---tarantool> print(fiber.time(), fiber.time()-start)1600785979.8291 1600537279.241---

fiber.clock64()

То же, что и fiber.clock(), но в микросекундах.

Возвращает

количество секунд в виде 64-битного целого числа, представляющее прошедшее время по настенным часам с некоторого момента в прошлом, который гарантированно не изменяется в течение жизни процесса.

Тип возвращаемого значения

cdata (ctype<int64_t>)

fiber_object

fiber_object:id()

Параметры:

  • fiber_object — как правило, это объект, на который ссылается возвращаемое значение fiber.create или fiber.self или fiber.find

Возвращает

ID файбера.

Тип возвращаемого значения

number

fiber.self():id() может также быть выражен как fiber.id().

Пример:

tarantool> fiber_object = fiber.self()---tarantool> fiber_object:id()---- 101

fiber_object:name()

Параметры:

  • fiber_object — как правило, это объект, на который ссылается возвращаемое значение fiber.create или fiber.self или fiber.find

Возвращает

имя файбера.

Тип возвращаемого значения

string

fiber.self():name() может также быть выражен как fiber.name().

Пример:

tarantool> fiber.self():name()---- interactive

fiber_object:name(name[, options])

Изменение имени файбера. По умолчанию файбер интерактивного режима сервера Tarantool называется 'interactive', а новые файберы, созданные с помощью fiber.create, называются 'lua'. Задание файберам отдельных имен упрощает их различение при использовании fiber.info и fiber.top(). Максимальная длина имени — 255.

Параметры:

  • fiber_object — как правило, это объект, на который ссылается возвращаемое значение fiber.create или fiber.self или fiber.find
  • name (string) — новое имя файбера.
  • options:
    • truncate=true – усекает имя до максимальной длины, если оно слишком длинное. Если этот параметр равен false (по умолчанию), fiber.name(new_name) выдает исключение, если новое имя слишком длинное. Максимальная длина имени — 255 (начиная с версии 2.4.1).

Возвращает

nil

Пример:

tarantool> fiber.self():name('non-interactive')---

fiber_object:status()

Возврат статуса указанного файбера.

Параметры:

  • fiber_object — как правило, это объект, на который ссылается возвращаемое значение fiber.create или fiber.self или fiber.find

Возвращает

статус файбера. Одно из значений: «dead», «suspended» или «running».

Тип возвращаемого значения

string

fiber.self():status() можно также записать как fiber.status().

Пример:

tarantool> fiber.self():status()---- running

fiber_object:cancel()

Отправка запроса на отмену файбера. Работающие и приостановленные файберы можно отменить. После отмены файбера попытки работать с ним приводят к ошибкам, например, fiber_object:name() вызывает error: the fiber is dead. Но завершенный файбер все еще может сообщить свой ID и статус.

Отмена файбера происходит асинхронно. Чтобы дождаться окончания отмены, используйте fiber_object:join(). После вызова fiber_object:cancel() файбер может проверить, был ли он удален. Если он этого не сделает, его отменить невозможно.

Параметры:

  • fiber_object — как правило, это объект, на который ссылается возвращаемое значение fiber.create или fiber.self или fiber.find

Возвращает

nil

Возможные ошибки:

нельзя отменить указанный объект файбера.

Пример:

См. пример для fiber.sleep().

fiber_object:set_max_slice(slice)

Устанавливает максимальный квант времени для файбера. Квант времени файбера ограничивает период выполнения файбера без передачи управления.

Параметры:

  • slice (number/table) — квант времени файбера, который может принимать одно из следующих значений:

    • период времени (в секундах), задающий квант ошибки. Пример: long_operation_fiber.set_max_slice(3).
    • таблица, задающая кванты предупреждения и ошибки (в секундах). Пример: long_operation_fiber.set_max_slice({warn = 1.5, err = 3}).

Пример:

В примере ниже показано, как использовать set_max_slice для ограничения кванта времени файбера. fiber.check_slice() вызывается внутри длительной операции, чтобы определить, истёк ли квант времени файбера.

-- app.lua --fiber = require('fiber')clock = require('clock')time = clock.monotonic()function long_operation()    while clock.monotonic() - time < 5 do        fiber.check_slice()        -- Long-running operation ⌛⌛⌛ --    endendlong_operation_fiber = fiber.new(long_operation)long_operation_fiber:set_max_slice({warn = 1.5, err = 3})

Вывод должен выглядеть следующим образом.

$ tarantool app.luafiber has not yielded for more than 1.500 secondsFiberSliceIsExceeded: fiber slice is exceeded

fiber_object.storage

Локальное хранилище внутри файбера. Это Lua-таблица, которая создается при первом обращении. Хранилище может содержать любое количество именованных значений с учетом ограничений памяти. Именование может выполняться с помощью {fiber_object}.storage.{name} или {fiber_object}.storage['{name}'] или с помощью числа {fiber_object}.storage[{number}]. Значениями могут быть числа или строки.

fiber.storage уничтожается при завершении файбера, независимо от того, как он завершен — через {fiber_object}:cancel() или с помощью return в функции файбера. Более того, хранилище очищается даже для файберов из пула, обслуживающих запросы IProto. Файберы из пула никогда по-настоящему не завершаются, но их хранилище очищается после каждого запроса. Это позволяет использовать fiber.storage как полноценное хранилище в рамках запроса. Такое поведение реализовано в версиях 2.2.3, 2.3.2, 2.4.1 и всех последующих.

Хранилище может быть создано для файбера независимо от того, как создан сам файбер — из C или из Lua. Например, файбер можно создать в C с помощью fiber_new(), затем он может выполнять вставку в спейс, в котором есть Lua-триггеры on_replace, и один из триггеров может создать fiber.storage. Это хранилище удаляется при остановке файбера.

Пример:

В примере ниже показано, как сохранить последнее введенное имя в хранилище файбера и получить это значение перед отменой файбера.

-- app.lua --fiber = require('fiber')function greet()    while true do        print('Enter a name:')        name = io.read()        if name ~= 'bye' then            fiber.self().storage.name = name            print('Hello, ' .. name)        else            print('Goodbye, ' .. fiber.self().storage['name'])            fiber.self():cancel()        end    endendfiber_object = fiber.create(greet)

Вывод может выглядеть следующим образом:

$ tarantool app.luaEnter a name:JohnHello, JohnEnter a name:JaneHello, JaneEnter a name:byeGoodbye, Jane

См. также box.session.storage.

fiber_object:set_joinable(is_joinable)

Делает файбер присоединяемым. Присоединяемый файбер можно ожидать с помощью fiber_object:join().

Лучше всего вызывать fiber_object:set_joinable() до начала выполнения функции файбера, так как в противном случае файбер может перейти в состояние dead до того, как fiber_object:set_joinable() вступит в силу. Обычная последовательность действий:

  1. Вызовите fiber.new() вместо fiber.create(), чтобы создать новый fiber_object. Не передавайте управление, поскольку это приведет к началу работы функции файбера.
  2. Вызовите fiber_object:set_joinable(true), чтобы сделать новый fiber_object присоединяемым. Теперь можно передать управление.
  3. Вызовите fiber_object:join(). Как правило, следует вызвать fiber_object:join(), в противном случае статус файбера может перейти в 'suspended' (приостановлен) после выполнения функции, а не 'dead' (завершен).

Параметры:

  • is_joinable (boolean) — логическое значение, указывающее, является ли файбер присоединяемым

Возвращает

nil

Пример:

См. пример для fiber_object:join().

fiber_object:join([timeout])

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

Присоединение запускает функцию файбера и ожидает перехода статуса файбера в dead. Обычно статус становится dead по завершении выполнения функции. Присоединение вызывает передачу управления, поэтому, если файбер находится в состоянии suspended, выполнение его функции возобновляется.

Обратите внимание, что присоединение работает только если файбер создан с помощью fiber.new() и сделан присоединяемым с помощью fiber_object:set_joinable().

Параметры:

  • timeout (number) — максимальное количество секунд ожидания завершения файбера. По умолчанию: бесконечность.

Возвращает

Метод join возвращает два значения:

  • Логическое значение, которое показывает, успешно ли завершилась функция файбера.
  • Возвращаемое значение функции файбера.

Если первое значение — false, значит функция файбера завершилась аварийно, а второй результат содержит сведения об ошибке, которые можно распаковать так же, как результат pcall.

Тип возвращаемого значения

boolean + result type, or boolean + struct error

Возможные ошибки:

файбер уже присоединен параллельным вызовом fiber:join().

Пример:

В примере ниже показано, как получить результат, возвращенный функцией файбера.

fiber = require('fiber')function add(a, b)    return a + bendadd_fiber = fiber.new(add, 5, 6)add_fiber:set_joinable(true)is_success, result = add_fiber:join()print('Is successful: '.. tostring(is_success))print('Returned value: '..result)

Вывод должен выглядеть следующим образом.

$ tarantool app.luaIs successful: trueReturned value: 11

Пример ошибки при передаче управления

Предупреждение: функция yield() и любая функция, которая неявно передает управление (например, sleep()), может упасть (выдать исключение).

Например, в этой функции есть цикл, выполняющийся до вызова cancel(). Последнее, что будет выведено — 'before yield', что демонстрирует ошибку при выполнении yield(): цикл не продолжился до следующей проверки testcancel().

fiber = require('fiber')function function_name()  while true do    print('before testcancel')    fiber.testcancel()    print('before yield')    fiber.yield()  endendfiber_object = fiber.create(function_name)fiber.sleep(.1)fiber_object:cancel()

Каналы

Вызов fiber.channel() для создания и получение нового объекта канала.

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

Обмен сообщениями является синхронным. Сборщик мусора Lua помечает или освобождает канал, когда он больше не используется, как и любой другой объект Lua. Используйте объектно-ориентированный синтаксис, например, channel:put(message) вместо fiber.channel.put(message).

fiber.channel([capacity])

Создание нового канала связи.

Параметры:

  • capacity (int) — максимальное количество слотов (мест для сообщений channel:put), которые могут использоваться одновременно. Значение по умолчанию — 0.

Возвращает

новый объект канала. В выводе консоли он сериализуется как channel: [number], где [number] — возвращаемое значение channel_object:count().

Тип возвращаемого значения

userdata

channel_object

channel_object:put(message[, timeout])

Отправка сообщения по каналу связи. Если канал заполнен, channel:put() ожидает, пока не освободится слот в канале.

Значение по умолчанию для емкости канала — 0. При этом значении по умолчанию channel:put() ожидает бесконечно, пока не будет вызван channel:get().

Параметры:

  • message (lua-value) — отправляемое значение, обычно строка, число или таблица
  • timeout (number) — максимальное время ожидания освобождения слота в секундах. По умолчанию: бесконечность.

Возвращает

Если указан timeout и в течение указанного времени в канале нет свободного слота, возвращается false. Если канал закрыт, возвращается false. В остальных случаях возвращается true, что означает успешное выполнение.

Тип возвращаемого значения

boolean

channel_object:close()

Закрытие канала. Все, кто находится в режиме ожидания в канале, отключаются. Все последующие операции channel:get() вернут нулевое значение nil, а все последующие операции channel:put() вернут false (ложь).

channel_object:get([timeout])

Перехват и удаление сообщения из канала. Если канал пуст, channel:get() будет ожидать сообщения.

Параметры:

  • timeout (number) — максимальное время ожидания сообщения в секундах. По умолчанию: бесконечность.

Возвращает

Если указан timeout и в течение указанного времени в канале нет сообщений, возвращается nil. Если канал закрыт, возвращается nil. В остальных случаях возвращается сообщение, помещенное в канал с помощью channel:put().

Тип возвращаемого значения

обычно строка, число или таблица, в зависимости от того, что было передано в channel:put

channel_object:is_empty()

Проверка пустоты канала (отсутствие сообщений).

Возвращает

true, если канал пуст. В противном случае — false.

Тип возвращаемого значения

boolean

channel_object:count()

Определение количества сообщений в канале.

Возвращает

количество сообщений.

Тип возвращаемого значения

number

channel_object:is_full()

Проверка заполненности канала.

Возвращает

true, если канал заполнен (количество сообщений в канале равно количеству слотов, поэтому нет места для нового сообщения). В противном случае — false.

Тип возвращаемого значения

boolean

channel_object:has_readers()

Проверка пустого канала на наличие читателей в состоянии ожидания сообщения после отправки запросов channel:get().

Возвращает

true, если есть ожидающие читатели. В противном случае — false.

Тип возвращаемого значения

boolean

channel_object:has_writers()

Проверка полного канала на наличие писателей в состоянии ожидания после отправки запросов channel:put().

Возвращает

true, если есть ожидающие писатели. В противном случае — false.

Тип возвращаемого значения

boolean

channel_object:is_closed()

Проверка того, закрыт ли канал.

Возвращает

true, если канал уже закрыт. В противном случае — false.

Тип возвращаемого значения

boolean

Пример

В данном примере дается примерное представление о том, как должны выглядеть функции для файберов. Предполагается, что на функции ссылается fiber.create().

fiber = require('fiber')channel = fiber.channel(10)function consumer_fiber()    while true do        local task = channel:get()        ...    endendfunction consumer2_fiber()    while true do        -- 10 seconds        local task = channel:get(10)        if task ~= nil then            ...        else            -- timeout        end    endendfunction producer_fiber()    while true do        task = box.space...:select{...}        ...        if channel:is_empty() then            -- channel is empty        end        if channel:is_full() then            -- channel is full        end        ...        if channel:has_readers() then            -- there are some fibers            -- that are waiting for data        end        ...        if channel:has_writers() then            -- there are some fibers            -- that are waiting for readers        end        channel:put(task)    endendfunction producer2_fiber()    while true do        task = box.space...select{...}        -- 10 seconds        if channel:put(task, 10) then            ...        else            -- timeout        end    endend

Условные переменные

Вызов fiber.cond() используется для создания именованной условной переменной, которая будет называться 'cond' для примеров данного раздела.

Вызов cond:wait() используется, чтобы заставить файбер ожидать сигнал, с помощью условной переменной.

Вызов cond:signal() используется, чтобы отправить сигнал для пробуждения отдельного файбера, который выполнил запрос cond:wait().

Вызов cond:broadcast() используется для отправки сигнала всем файберам, которые выполнили cond:wait().

fiber.cond()

Создание новой условной переменной.

Возвращает

новая условная переменная.

Тип возвращаемого значения

объект Lua

cond_object

cond_object:wait([timeout])

Перевод файбера в режим ожидания до пробуждения другим файбером с помощью метода signal() или broadcast(). Переход в режим ожидания вызывает неявную передачу управления fiber.yield().

Параметры:

  • timeout (number) — количество секунд ожидания, по умолчанию = бесконечно.

Возвращает

Если задан timeout и сигнал не поступает в течение указанного времени ожидания, wait() возвращает false. Если поступает сигнал или широковещательное сообщение, wait() возвращает true.

Тип возвращаемого значения

boolean

cond_object:signal()

Пробуждение отдельного файбера, который выполнил wait() для той же переменной. Не выполняет передачу управления (yield).

Тип возвращаемого значения

nil

cond_object:broadcast()

Пробуждение всех файберов, которые выполнили wait() для той же переменной. Не выполняет передачу управления (yield).

Тип возвращаемого значения

nil

Пример

Предположим, что экземпляр Tarantool запущен и принимает подключения на localhost, порт 3301. Предположим, что гостевые пользователи имеют права на подключение. Для запуска двух клиентов будет использоваться утилита tt.

В первом терминале введите:

$ tt connect localhost:3301tarantool> fiber = require('fiber')tarantool> cond = fiber.cond()tarantool> cond:wait()

Задача повиснет, поскольку cond:wait() – без дополнительного аргумента времени ожидания timeout – уйдет в режим ожидания до изменения условной переменной.

Во втором терминале введите:

$ tt connect localhost:3301tarantool> cond:signal()

Теперь снова взгляните на терминал №1. Он покажет, что ожидание прекратилось, и функция cond:wait() вернула значение true.

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