Module fiber | Tarantool
Документация на русском языке
поддерживается сообществом

Module fiber

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

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

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

Имя Назначение
Fibers
fiber.create() Создание и запуск файбера
fiber.new() Создание файбера без запуска
fiber.self() Получение объекта файбера
fiber.find() Получение объекта файбера по ID
fiber.sleep() Перевод файбера в режим ожидания
fiber.yield() Передача управления
fiber.status() Получение статуса активного файбера
fiber.info() Получение информации о всех файберах
fiber.top() Возврат таблицы с активными файберами и отображение статистики потребления ресурсов ЦП
fiber.kill() Отмена файбера
fiber.testcancel() Проверка отмены действующего файбера
fiber.set_max_slice() Set the default maximum slice for all fibers
fiber.set_slice() Set a slice for the current fiber execution
fiber.extend_slice() Extend a slice for the current fiber execution
fiber.check_slice() Check whether a slice for the current fiber is over
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() Set a fiber’s maximum slice
fiber_object.storage Локальное хранилище в пределах файбера
fiber_object:set_joinable() Создание возможности подключения нового файбера
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 A useful example about channels
Condition variables
fiber.cond() Создание условной переменной
cond_object:wait() Перевод файбера в режим ожидания до пробуждения другим файбером
cond_object:signal() Пробуждение отдельного файбера
cond_object:broadcast() Пробуждение всех файберов
Example A useful example about condition variables

A fiber is a set of instructions that are executed with cooperative multitasking. The fiber module enables you to create a fiber and associate it with a user-supplied function called a fiber function.

A fiber has the following possible states: running, suspended, ready, or dead. A program with fibers is, at any given time, running only one of its fibers. This running fiber only suspends its execution when it explicitly yields control to another fiber that is ready to execute.

When the fiber function ends, the fiber ends and becomes dead. If required, you can cancel a running or suspended fiber. Another useful capability is limiting a fiber execution time for long-running operations.

Примечание

By default, each transaction in Tarantool is executed in a single fiber on a single thread, sees a consistent database state, and commits all changes atomically.

To create a fiber, call one of the following functions:

  • fiber.create() creates a fiber and runs it immediately. The initial fiber state is running.
  • fiber.new() creates a fiber but does not start it. The initial fiber state is ready. You can join such fibers by calling the fiber_object:join() function and get the result returned by the fiber’s function.

Yield is an action that occurs in a cooperative environment that transfers control of the thread from the current fiber to another fiber that is ready to execute. The fiber module provides the following functions that yield control to another fiber explicitly:

  • fiber.yield() yields control to the scheduler.
  • fiber.sleep() yields control to the scheduler and sleeps for the specified number of seconds.

To cancel a fiber, use the fiber_object.cancel function. You can also call fiber.kill() to locate a fiber by its numeric ID and cancel it.

If a fiber works too long without yielding control, you can use a fiber slice to limit its execution time. The fiber_slice_default compat option controls the default value of the maximum fiber slice.

There are two slice types: a warning and an error slice.

  • When a warning slice is over, a warning message is logged, for example:

    fiber has not yielded for more than 0.500 seconds
    
  • When an error slice is over, the fiber is cancelled and the FiberSliceIsExceeded error is thrown:

    FiberSliceIsExceeded: fiber slice is exceeded
    

    Control is passed to another fiber that is ready to execute.

The fiber slice is checked by all functions operating on spaces and indexes, such as index_object.select(), space_object.replace(), and so on. You can also use the fiber.check_slice() function in application code to check whether the slice for the current fiber is over.

The following functions override the the default value of the maximum fiber slice:

The maximum slice is set when a fiber wakes up. This might be its first run or wake up after fiber.yield().

You can change or increase the slice for a current fiber’s execution using the following functions:

Note that the specified values don’t affect a fiber’s execution after fiber.yield().

To get information about all fibers or a specific fiber, use the following functions:

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

A fiber has all the features of a Lua coroutine and all the programming concepts that apply to Lua coroutines apply to fibers as well. However, Tarantool has made some enhancements for fibers and has used fibers internally. So, although the use of coroutines is possible and supported, the use of fibers is recommended.

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

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

Параметры:
  • function – функция, которая будет связана с файбером
  • function-arguments – arguments to be passed to the function
возвращает:

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

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

пользовательские данные

Пример:

The script below shows how to create a fiber using fiber.create:

-- app.lua --
fiber = require('fiber')

function greet(name)
    print('Hello, '..name)
end

greet_fiber = fiber.create(greet, 'John')
print('Fiber already started')

The following output should be displayed after running app.lua:

$ tarantool app.lua
Hello, John
Fiber already started
fiber.new(function[, function-arguments])

Create a fiber but do not start it. The created fiber starts after the fiber creator (that is, the job that is calling fiber.new()) yields. The initial fiber state is ready.

Примечание

Note that fiber.status() returns the suspended state for ready fibers because the ready state is not observable using the fiber module API.

You can join fibers created using fiber.new by calling the fiber_object:join() function and get the result returned by the fiber’s function. To join the fiber, you need to make it joinable using fiber_object:set_joinable().

Параметры:
  • function – функция, которая будет связана с файбером
  • function-arguments – arguments to be passed to the function
возвращает:

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

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

пользовательские данные

Пример:

The script below shows how to create a fiber using fiber.new:

-- app.lua --
fiber = require('fiber')

function greet(name)
    print('Hello, '..name)
end

greet_fiber = fiber.new(greet, 'John')
print('Fiber not started yet')

The following output should be displayed after running app.lua:

$ tarantool app.lua
Fiber not started yet
Hello, John
fiber.self()
возвращает:объект файбера для запланированного на данный момент файбера.
тип возвращаемого значения:
 пользовательские данные

Пример:

tarantool> fiber.self()
---
- status: running
  name: interactive
  id: 101
...
fiber.find(id)
Параметры:
  • id – числовой идентификатор файбера.
возвращает:

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

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

пользовательские данные

Пример:

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

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

Параметры:
  • time – количество секунд в режиме ожидания.
Исключение:

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

Пример:

The increment function below contains an infinite loop that adds 1 to the counter global variable. Then, the current fiber goes to sleep for period seconds. sleep causes an implicit fiber.yield().

-- app.lua --
fiber = require('fiber')

counter = 0
function increment(period)
    while true do
        counter = counter + 1
        fiber.sleep(period)
    end
end

increment_fiber = fiber.create(increment, 2)
require('console').start()

After running the script above, print the information about the fiber: a fiber ID, its status, and the counter value.

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

Then, cancel the fiber and print the information about the fiber one more time. This time the fiber status is dead.

tarantool> increment_fiber:cancel()
---
...

tarantool> print('ID: ' .. increment_fiber:id() .. '\nStatus: ' .. increment_fiber:status() .. '\nCounter: ' .. counter)
ID: 104
Status: dead
Counter: 12
---
...
fiber.yield()

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

Исключение:см. Пример неудачной передачи управления

Пример:

In the example below, two fibers are associated with the same function. Each fiber yields control after printing a greeting.

-- 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()
    end
end

for i = 1, 2 do
    fiber_object = fiber.create(greet)
    fiber_object:cancel()
end

The output might look as follows:

$ tarantool app.lua
Enter a name:
John
Hello, John. I am fiber 104
Enter a name:
Jane
Hello, Jane. I am fiber 105
fiber.status([fiber_object])

Return the status of the current fiber. If the fiber_object is passed, return the status of the specified fiber.

Параметры:
  • fiber_object – (optional) the fiber object
возвращает:

the status of fiber. One of: dead, suspended, or running.

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

строка

Пример:

tarantool> fiber.status()
---
- running
...
fiber.info({[backtrace/bt]})

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

Параметры:
  • backtrace (boolean) – show backtrace. Default: true. Set to false to show less information (symbol resolving can be expensive).
  • bt (boolean) – same as backtrace, but with lower priority.
возвращает:

number of context switches (csw), backtrace, total memory, used memory, fiber ID (fid), fiber name. If fiber.top is enabled or Tarantool was built with ENABLE_FIBER_TOP, processor time (time) is also returned.

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

таблица

Return values explained

  • csw – number of context switches.
  • backtrace, bt – each fiber’s stack trace, showing where it originated and what functions were called.
  • memory:
    • total – total memory occupied by the fiber as a C structure, its stack, etc.
    • used – actual memory used by the fiber.
  • time – duplicates the «time» entry from fiber.top().cpu for each fiber.
    Only shown if fiber.top is enabled.

Пример:

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 (in percent), which indicates the share of time the fiber was executing during the previous event loop iteration.

  2. average (in percent), which is calculated as an exponential moving average of instant values over all the previous event loop iterations.

  3. time (в секундах) определяет процессорное время, потраченное на обработку каждого файбера за время его существования.

    Запись time также добавляется к выводу информации о файбере с помощью fiber.info() (дублируется запись time из fiber.top().cpu для каждого файбера).

    Обратите внимание, что подсчет time ведется, только если активна функция fiber.top().

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

Примечание

With 2.11.0, cpu_misses is deprecated and always returns 0.

Пример:

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
...

Notice that by default new fibers created due to fiber.create are named „lua“ so it is better to set their names explicitly via fiber_object:name(„name“).

There are several system fibers in fiber.top() output that might be useful:

  • sched is a special system fiber. It schedules tasks to other fibers, if any, and also handles some libev events.

    It can have high instant and average values in fiber.top() output in two cases:

    • The instance has almost no load - then practically only sched is executing, and the other fibers are sleeping. So relative to the other fibers, sched may have almost 100% load.
    • sched handles a large number of system events. This should not cause performance problems.
  • main fibers process requests that come over the network (iproto requests). There are several such fibers, and new ones are created if needed. When a new request comes in, a free fiber takes it and executes it. The request can be a typical select/replace/delete/insert or a function call. For example, conn:eval() or conn:call().

Примечание

Enabling fiber.top() slows down fiber switching by about 15%, so it is disabled by default. To enable it, use fiber.top_enable(). To disable it after you finished debugging, use fiber.top_disable().

fiber.kill(id)

Locate a fiber by its numeric ID and cancel it. In other words, fiber.kill() combines fiber.find() and fiber_object:cancel().

Параметры:
  • id – the ID of the fiber to be cancelled.
Исключение:

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

Пример:

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

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

Примечание

Даже при исключении файбер будет отменен. Большинство вызовов проверяют fiber.testcancel(). Однако некоторые функции (id, status, join и т.д.) не вернут ошибку. Мы рекомендуем разработчикам приложений реализовать случайные проверки fiber.testcancel() и максимально быстро завершить выполнение файбера, если он был отменен.

Пример:

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

Set the default maximum slice for all fibers. A fiber slice limits the time period of executing a fiber without yielding control.

Параметры:
  • slice (number/table) –

    a fiber slice, which can one of the following:

    • a time period (in seconds) that specifies the error slice. Example: fiber.set_max_slice(3).
    • a table that specifies the warning and error slices (in seconds). Example: fiber.set_max_slice({warn = 1.5, err = 3}).

Пример:

The example below shows how to use set_max_slice to limit the slice for all fibers. fiber.check_slice() is called inside a long-running operation to determine whether a slice for the current fiber is over.

-- 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 ⌛⌛⌛ --
    end
end

long_operation_fiber = fiber.create(long_operation)

The output should look as follows:

$ tarantool app.lua
fiber has not yielded for more than 1.500 seconds
FiberSliceIsExceeded: fiber slice is exceeded
fiber.set_slice(slice)

Set a slice for the current fiber execution. A fiber slice limits the time period of executing a fiber without yielding control.

Параметры:
  • slice (number/table) –

    a fiber slice, which can one of the following:

    • a time period (in seconds) that specifies the error slice. Example: fiber.set_slice(3).
    • a table that specifies the warning and error slices (in seconds). Example: fiber.set_slice({warn = 1.5, err = 3}).

Пример:

The example below shows how to use set_slice to limit the slice for the current fiber execution. fiber.check_slice() is called inside a long-running operation to determine whether a slice for the current fiber is over.

-- 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 ⌛⌛⌛ --
    end
end

long_operation_fiber = fiber.create(long_operation)

The output should look as follows.

$ tarantool app.lua
fiber has not yielded for more than 1.500 seconds
FiberSliceIsExceeded: fiber slice is exceeded
fiber.extend_slice(slice)

Extend a slice for the current fiber execution. For example, if the default error slice is set using fiber.set_max_slice() to 3 seconds, extend_slice(1) extends the error slice to 4 seconds.

Параметры:
  • slice (number/table) –

    a fiber slice, which can one of the following:

    • a time period (in seconds) that specifies the error slice. Example: fiber.extend_slice(1).
    • a table that specifies the warning and error slices (in seconds). Example: fiber.extend_slice({warn = 0.5, err = 1}).

Пример:

The example below shows how to use extend_slice to extend the slice for the current fiber execution. The default fiber slice is set using 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 ⌛⌛⌛ --
    end
end

long_operation_fiber = fiber.create(long_operation)

The output should look as follows.

$ tarantool app.lua
fiber has not yielded for more than 2.000 seconds
FiberSliceIsExceeded: fiber slice is exceeded

FiberSliceIsExceeded is thrown after 4 seconds.

fiber.check_slice()

Check whether a slice for the current fiber is over. A fiber slice limits the time period of executing a fiber without yielding control.

Пример:

See the examples for the following functions:

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

Пример:

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() сообщает системное время, а оно может меняться при изменениях в системе.

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

Пример:

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>)
object fiber_object
fiber_object:id()
Параметры:
  • fiber_object – как правило, это объект, полученный в результате вызова fiber.create, fiber.self или fiber.find
возвращает:

ID of the fiber.

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

число

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
возвращает:

имя файбера.

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

строка

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

Пример:

tarantool> fiber.self():name()
---
- interactive
...
fiber_object:name(name[, options])

Change the fiber name. By default a Tarantool server’s interactive-mode fiber is named „interactive“ and new fibers created due to fiber.create are named „lua“. Giving fibers distinct names makes it easier to distinguish them when using fiber.info and fiber.top(). Max length is 255.

Параметры:
  • fiber_object – как правило, это объект, полученный в результате вызова fiber.create, fiber.self или fiber.find
  • name (string) – новое имя файбера.
  • options
    • truncate=true – truncates the name to the max length if it is too long. If this option is false (the default), fiber.name(new_name) fails with an exception if a new name is too long. The name length limit is 255 (since version 2.4.1).
возвращает:

nil

Пример:

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

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

Параметры:
  • fiber_object – как правило, это объект, полученный в результате вызова fiber.create, fiber.self или fiber.find
возвращает:

статус файбера: “dead” (недоступен), “suspended” (приостановлен) или “running” (активен).

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

строка

fiber.self():status() can also be expressed as fiber.status().

Пример:

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

Send a cancellation request to the fiber. Running and suspended fibers can be cancelled. After a fiber has been cancelled, attempts to operate on it cause errors, for example, fiber_object:name() causes error: the fiber is dead. But a dead fiber can still report its ID and status.

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

Параметры:
  • fiber_object – как правило, это объект, полученный в результате вызова fiber.create, fiber.self или fiber.find
возвращает:

nil

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

Пример:

See the fiber.sleep() example.

fiber_object:set_max_slice(slice)

Set a fiber’s maximum slice. A fiber slice limits the time period of executing a fiber without yielding control.

Параметры:
  • slice (number/table) –

    a fiber slice, which can one of the following:

    • a time period (in seconds) that specifies the error slice. Example: long_operation_fiber.set_max_slice(3).
    • a table that specifies the warning and error slices (in seconds). Example: long_operation_fiber.set_max_slice({warn = 1.5, err = 3}).

Пример:

The example below shows how to use set_max_slice to limit the fiber slice. fiber.check_slice() is called inside a long-running operation to determine whether a slice for the fiber is over.

-- 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 ⌛⌛⌛ --
    end
end

long_operation_fiber = fiber.new(long_operation)
long_operation_fiber:set_max_slice({warn = 1.5, err = 3})

The output should look as follows.

$ tarantool app.lua
fiber has not yielded for more than 1.500 seconds
FiberSliceIsExceeded: fiber slice is exceeded
fiber_object.storage

A local storage within the fiber. It is a Lua table created when it is first accessed. The storage can contain any number of named values, subject to memory limitations. Naming may be done with fiber_object.storage.name or fiber_object.storage['name']. or with a number fiber_object.storage[number]. Values may be either numbers or strings.

fiber.storage is destroyed when the fiber is finished, regardless of how is it finished – via fiber_object:cancel(), or the fiber’s function did „return“. Moreover, the storage is cleaned up even for pooled fibers used to serve IProto requests. Pooled fibers never really die, but nonetheless their storage is cleaned up after each request. That makes possible to use fiber.storage as a full featured request-local storage. This behavior is implemented in versions 2.2.3, 2.3.2, 2.4.1, and all later versions.

This storage may be created for a fiber, no matter how the fiber itself is created – from C or from Lua. For example, a fiber can be created in C using fiber_new(), then it can insert into a space, which has Lua on_replace triggers, and one of the triggers can create fiber.storage. That storage is deleted when the fiber is stopped.

Пример:

The example below shows how to save the last entered name in a fiber storage and get this value before cancelling a fiber.

-- 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
    end
end

fiber_object = fiber.create(greet)

The output might look as follows:

$ tarantool app.lua
Enter a name:
John
Hello, John
Enter a name:
Jane
Hello, Jane
Enter a name:
bye
Goodbye, Jane

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

fiber_object:set_joinable(is_joinable)

Make a fiber joinable. A joinable fiber can be waited for using fiber_object:join().

The best practice is to call fiber_object:set_joinable() before the fiber function begins to execute because otherwise the fiber could become dead before fiber_object:set_joinable() takes effect. The usual sequence could be:

  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) – the boolean value that specifies whether the fiber is joinable
возвращает:

nil

Пример:

See the fiber_object.join() example.

fiber_object:join()

Join a fiber. Joining a fiber enables you to get the result returned by the fiber’s function.

Joining a fiber runs the fiber’s function and waits until the fiber’s status is dead. Normally a status becomes dead when the function execution finishes. Joining the fiber causes a yield, therefore, if the fiber is currently in the suspended state, execution of its fiber function resumes.

Note that joining a fiber works only if the fiber is created using fiber.new() and is made joinable using fiber_object:set_joinable().

возвращает:

The join method returns two values:

  • The boolean value that indicates whether the join is succeeded because the fiber’s function ended normally.
  • The return value of the fiber’s function.

If the first value is false, then the join succeeded because the fiber’s function ended abnormally and the second result has the details about the error, which one can unpack in the same way that one unpacks a pcall result.

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

boolean + result type, or boolean + struct error

Пример:

The example below shows how to get the result returned by the fiber’s function.

fiber = require('fiber')

function add(a, b)
    return a + b
end

add_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)

The output should look as follows.

$ tarantool app.lua
Is successful: true
Returned value: 11

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

For example, this function has a loop that repeats until cancel() happens. The last thing that it will print is „before yield“, which demonstrates that yield() failed, the loop did not continue until testcancel() failed.

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

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

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

Message exchange is synchronous. The Lua garbage collector will mark or free the channel when no one is using it, as with any other Lua object. Use object-oriented syntax, for example, channel:put(message) rather than fiber.channel.put(message).

fiber.channel([capacity])

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

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

новый объект — канал.

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

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

object channel_object
channel_object:put(message[, timeout])

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

Примечание

The default channel capacity is 0. With this default value, channel:put() waits infinitely until channel:get() is called.

Параметры:
  • 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()

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

возвращает:количество сообщений.
тип возвращаемого значения:
 число
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()
         ...
     end
 end

 function consumer2_fiber()
     while true do
         -- 10 секунд
         local task = channel:get(10)
         if task ~= nil then
             ...
         else
             -- время ожидания
         end
     end
 end

 function producer_fiber()
     while true do
         task = box.space...:select{...}
         ...
         if channel:is_empty() then
             -- канал пуст
         end

         if channel:is_full() then
             -- канал полон
         end

         ...
         if channel:has_readers() then
             -- есть файберы
             -- которые ожидают данные
         end
         ...

         if channel:has_writers() then
             -- есть файберы
             -- которые ожидают читателей
         end
         channel:put(task)
     end
 end

 function producer2_fiber()
     while true do
         task = box.space...select{...}
         -- 10 секунд
         if channel:put(task, 10) then
             ...
         else
             -- время ожидания
         end
     end
 end

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

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

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

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

fiber.cond()

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

возвращает:новая условная переменная.
тип возвращаемого значения:
 Lua-объект
object cond_object
cond_object:wait([timeout])

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

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

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

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

boolean (логический)

cond_object:signal()

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

тип возвращаемого значения:
 nil
cond_object:broadcast()

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

тип возвращаемого значения:
 nil

Assume that a Tarantool instance is running and listening for connections on localhost port 3301. Assume that guest users have privileges to connect. We will use the tt utility to start two clients.

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

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

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

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

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

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

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

Нашли ответ на свой вопрос?
Обратная связь