Module fiber
With the fiber module, you can:
- Create, run, and manage fibers.
- Send and receive messages between different processes (i.e. different connections, sessions, or fibers) via channels.
- Use a synchronization mechanism for fibers,
similar to "condition variables" and similar to operating-system
functions, such as
pthread_cond_wait()pluspthread_cond_signal().
Below is a list of all fiber functions and members.
Name | Use |
|---|---|
Fibers | |
Create and start a fiber | |
Create but do not start a fiber | |
Get a fiber object | |
Get a fiber object by ID | |
Make a fiber go to sleep | |
Yield control | |
Get the current fiber's status | |
Get information about all fibers | |
Return a table of alive fibers and show their CPU consumption | |
Cancel a fiber | |
Check if the current fiber has been cancelled | |
Set the default maximum slice for all fibers | |
Set a slice for the current fiber execution | |
Extend a slice for the current fiber execution | |
Check whether a slice for the current fiber is over | |
Get the system time in seconds | |
Get the system time in microseconds | |
Get the monotonic time in seconds | |
Get the monotonic time in microseconds | Fiber object |
Get a fiber's ID | |
Get a fiber's name | |
Set a fiber's name | |
Get a fiber's status | |
Cancel a fiber | |
Set a fiber's maximum slice | |
Local storage within the fiber | |
Make it possible for a new fiber to join | |
Wait for a fiber's state to become 'dead' | |
Channels | |
Create a communication channel | |
Send a message via a channel | |
Close a channel | |
Fetch a message from a channel | |
Check if a channel is empty | |
Count messages in a channel | |
Check if a channel is full | |
Check if an empty channel has any readers waiting | |
Check if a full channel has any writers waiting | |
Check if a channel is closed | |
A useful example about channels | Condition variables |
Create a condition variable | |
Make a fiber go to sleep until woken by another fiber | |
Wake up a single fiber | |
Wake up all fibers | |
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.
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
FiberSliceIsExceedederror is thrown:FiberSliceIsExceeded: fiber slice is exceededControl 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:
- fiber.set_max_slice(slice) sets the default maximum slice for all fibers.
- fiber_object:set_max_slice(slice) sets the maximum slice for a particular fiber.
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:
- fiber.set_slice(slice) sets the slice for a current fiber execution.
- fiber.extend_slice(slice) extends the slice for a current fiber execution.
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:
- fiber.info returns information about all fibers.
- fiber.status() gets the current fiber's status. To get the status of the specified fiber, call fiber_object:status().
- fiber.top() shows all alive fibers and their CPU consumption.
Like all Lua objects, dead fibers are garbage collected. The Lua garbage collector frees pool allocator memory owned by the fiber, resets all fiber data, and returns the fiber (now called a fiber carcass) to the fiber pool. The carcass can be reused when another fiber is created.
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.
Create and start a fiber. The fiber is created and begins to run immediately.
Parameters:
-
function— the function to be associated with the fiber -
function-arguments— arguments to be passed to the function
Returns
created fiber object
Return type
userdata
Example:
The script below shows how to create a fiber using fiber.create:
-- app.lua --fiber = require('fiber')function greet(name)print('Hello, '..name)endgreet_fiber = fiber.create(greet, 'John')print('Fiber already started')
The following output should be displayed after
running app.lua:
$ tarantool app.luaHello, JohnFiber already started
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.
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— the function to be associated with the fiber -
function-arguments— arguments to be passed to the function
Returns
created fiber object
Return type
userdata
Example:
The script below shows how to create a fiber using fiber.new:
-- app.lua --fiber = require('fiber')function greet(name)print('Hello, '..name)endgreet_fiber = fiber.new(greet, 'John')print('Fiber not started yet')
The following output should be displayed after
running app.lua:
$ tarantool app.luaFiber not started yetHello, John
Returns
fiber object for the currently scheduled fiber.
Return type
userdata
Example:
tarantool> fiber.self()---- status: runningname: interactiveid: 101...
Parameters:
id— numeric identifier of the fiber.
Returns
fiber object for the specified fiber.
Return type
userdata
Example:
tarantool> fiber.find(101)---- status: runningname: interactiveid: 101...
Yield control to the scheduler and sleep for the specified number of seconds. Only the current fiber can be made to sleep.
Parameters:
time— number of seconds to sleep.
Exception : see the Example of yield failure.
Example:
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 = 0function increment(period)while true docounter = counter + 1fiber.sleep(period)endendincrement_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: 104Status: suspendedCounter: 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: 104Status: deadCounter: 12---...
Yield control to the scheduler. Equivalent to fiber.sleep(0).
Exception : see the Example of yield failure.
Example:
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 doprint('Enter a name:')name = io.read()print('Hello, '..name..'. I am fiber '..fiber.id())fiber.yield()endendfor i = 1, 2 dofiber_object = fiber.create(greet)fiber_object:cancel()end
The output might look as follows:
$ tarantool app.luaEnter a name:JohnHello, John. I am fiber 104Enter a name:JaneHello, Jane. I am fiber 105
Return the status of the current fiber. If the fiber_object is passed,
return the status of the specified fiber.
Parameters:
fiber_object— (optional) the fiber object
Returns
the status of fiber. One of: dead, suspended, or running.
Return type
string
Example:
tarantool> fiber.status()---- running...
Return information about all fibers.
Parameters:
-
backtrace(boolean) — show backtrace. Default:true. Set tofalseto show less information (symbol resolving can be expensive). -
bt(boolean) — same asbacktrace, but with lower priority.
Returns
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 type
table
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.
Example:
tarantool> fiber.info({ bt = true })---- 101:csw: 1backtrace:- 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: 516472used: 0time: 0name: luafid: 101102:csw: 0backtrace:- C: '#0 (nil) in +63'- C: '#1 (nil) in +63'memory:total: 516472used: 0time: 0name: on_shutdownfid: 102...
Show all alive fibers and their CPU consumption.
Returns
a table with two entries: cpu and cpu_misses
cpu itself is a table whose keys are strings containing fiber ids and
names. The three metrics available for each fiber are:
-
instant(in percent), which indicates the share of time the fiber was executing during the previous event loop iteration. -
average(in percent), which is calculated as an exponential moving average of instant values over all the previous event loop iterations. -
time(in seconds), which estimates how much CPU time each fiber spent processing during its lifetime.The
timeentry is also added to each fiber's output infiber.info()(it duplicates thetimeentry fromfiber.top().cpuper fiber).Note that
timeis only counted whilefiber.top()is enabled.
cpu_misses indicates the number of times the TX thread detected it was
rescheduled on a different CPU core during the last event loop
iteration. fiber.top() uses the CPU timestamp counter to measure each
fiber's execution time. However, each CPU core may have its own counter
value (you can only rely on counter deltas if both measurements were
taken on the same core, otherwise the delta may even get negative). When
the TX thread is rescheduled to a different CPU core, Tarantool just
assumes the CPU delta was zero for the latest measurement. This lowers
the precision of our computations, so the bigger cpu misses value the
lower the precision of fiber.top() results.
Example:
tarantool> fiber.top()---- cpu:107/lua:instant: 30.967324490456time: 0.351821993average: 25.582738345233104/lua:instant: 9.6473633128437time: 0.110869897average: 7.9693406131877101/on_shutdown:instant: 0time: 0average: 0103/lua:instant: 9.8026528631511time: 0.112641118average: 18.138387232255106/lua:instant: 20.071174377224time: 0.226901357average: 17.077908441831102/interactive:instant: 0time: 9.6858e-05average: 0105/lua:instant: 9.2461986412164time: 0.10657528average: 7.70684586308271/sched:instant: 20.265286315108time: 0.237095335average: 23.141537169257cpu_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:
-
schedis a special system fiber. It schedules tasks to other fibers, if any, and also handles somelibevevents.It can have high
instantandaveragevalues infiber.top()output in two cases:- The instance has almost no load - then practically only
schedis executing, and the other fibers are sleeping. So relative to the other fibers,schedmay have almost 100% load. schedhandles a large number of system events. This should not cause performance problems.
- The instance has almost no load - then practically only
-
mainfibers 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 typicalselect/replace/delete/insertor a function call. For example, conn:eval() or conn:call().
Locate a fiber by its numeric ID and cancel it. In other words, fiber.kill() combines fiber.find() and fiber_object:cancel().
Parameters:
id— the ID of the fiber to be cancelled.
Exception : the specified fiber does not exist or cancel is not permitted.
Example:
tarantool> fiber.kill(fiber.id()) -- kill self, may make program end---- error: fiber is cancelled...
Check if the current fiber has been cancelled and throw an exception if this is the case.
Example:
tarantool> fiber.testcancel()---- error: fiber is cancelled...
Set the default maximum slice for all fibers. A fiber slice limits the time period of executing a fiber without yielding control.
Parameters:
-
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}).
Example:
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 dofiber.check_slice()-- Long-running operation ⌛⌛⌛ --endendlong_operation_fiber = fiber.create(long_operation)
The output should look as follows:
$ tarantool app.luafiber has not yielded for more than 1.500 secondsFiberSliceIsExceeded: fiber slice is exceeded
Set a slice for the current fiber execution. A fiber slice limits the time period of executing a fiber without yielding control.
Parameters:
-
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}).
Example:
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 dofiber.check_slice()-- Long-running operation ⌛⌛⌛ --endendlong_operation_fiber = fiber.create(long_operation)
The output should look as follows.
$ tarantool app.luafiber has not yielded for more than 1.500 secondsFiberSliceIsExceeded: fiber slice is exceeded
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.
Parameters:
-
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}).
Example:
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 dofiber.check_slice()-- Long-running operation ⌛⌛⌛ --endendlong_operation_fiber = fiber.create(long_operation)
The output should look as follows.
$ tarantool app.luafiber has not yielded for more than 2.000 secondsFiberSliceIsExceeded: fiber slice is exceeded
FiberSliceIsExceeded is thrown after 4 seconds.
Check whether a slice for the current fiber is over. A fiber slice limits the time period of executing a fiber without yielding control.
Example:
See the examples for the following functions:
Returns
current system time (in seconds since the epoch) as a Lua number. The time is taken from the event loop clock, which makes this call very cheap, but still useful for constructing artificial tuple keys.
Return type
number
Example:
tarantool> fiber.time(), fiber.time()---- 1448466279.2415- 1448466279.2415...
Returns
current system time (in microseconds since the epoch) as a 64-bit integer. The time is taken from the event loop clock.
Return type
cdata (ctype<int64_t>)
Example:
tarantool> fiber.time(), fiber.time64()---- 1448466351.2708- 1448466351270762...
Get the monotonic time in seconds. It is better to use fiber.clock()
for calculating timeouts instead of fiber.time() because
fiber.time() reports real time so it is affected by system time
changes.
Returns
a floating-point number of seconds, representing elapsed wall-clock time since some time in the past that is guaranteed not to change during the life of the process
Return type
number
Example:
tarantool> start = fiber.clock()---...tarantool> print(start)248700.58805---...tarantool> print(fiber.time(), fiber.time()-start)1600785979.8291 1600537279.241---...
Same as fiber.clock() but in microseconds.
Returns
a number of seconds as 64-bit integer, representing elapsed wall-clock time since some time in the past that is guaranteed not to change during the life of the process
Return type
cdata (ctype<int64_t>)
Parameters:
fiber_object— generally this is an object referenced in the return from fiber.create or fiber.self or fiber.find
Returns
ID of the fiber.
Return type
number
fiber.self():id() can also be expressed as fiber.id().
Example:
tarantool> fiber_object = fiber.self()---...tarantool> fiber_object:id()---- 101...
fiber_object— generally this is an object referenced in the return from fiber.create or fiber.self or fiber.find
Returns
name of the fiber.
Return type
string
fiber.self():name() can also be expressed as fiber.name().
Example:
tarantool> fiber.self():name()---- interactive...
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— generally this is an object referenced in the return from fiber.create or fiber.self or fiber.find -
name(string) — the new name of the fiber. -
options— none -
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 is255(since version 2.4.1).
Returns
nil
Example:
tarantool> fiber.self():name('non-interactive')---...
Return the status of the specified fiber.
fiber_object— generally this is an object referenced in the return from fiber.create or fiber.self or fiber.find
Returns
the status of fiber. One of: "dead", "suspended", or "running".
Return type
string
fiber.self():status() can also be expressed as fiber.status().
Example:
tarantool> fiber.self():status()---- running...
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.
Cancellation is asynchronous. Use
fiber_object:join() to wait for the cancellation to
complete. After fiber_object:cancel() is called, the fiber may or may
not check whether it was cancelled. If the fiber does not check it, it
cannot ever be cancelled.
fiber_object— generally this is an object referenced in the return from fiber.create or fiber.self or fiber.find
Returns
nil
Possible errors: cancel is not permitted for the specified fiber object.
Example:
See the fiber.sleep() example.
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}).
Example:
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.
``[ lua – 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.``` bash$ tarantool app.luafiber has not yielded for more than 1.500 secondsFiberSliceIsExceeded: fiber slice is exceeded
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 </release/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.
Example:
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 doprint('Enter a name:')name = io.read()if name ~= 'bye' thenfiber.self().storage.name = nameprint('Hello, ' .. name)elseprint('Goodbye, ' .. fiber.self().storage['name'])fiber.self():cancel()endendendfiber_object = fiber.create(greet)
The output might look as follows:
$ tarantool app.luaEnter a name:JohnHello, JohnEnter a name:JaneHello, JaneEnter a name:byeGoodbye, Jane
See also box.session.storage.
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:
-
Call
fiber.new()instead offiber.create()to create a new fiber_object.Do not yield at this point, because that will cause the fiber function to begin.
-
Call
fiber_object:set_joinable(true)to make the new fiber_object joinable.Now it is safe to yield.
-
Call
fiber_object:join().Usually
fiber_object:join()should be called, otherwise the fiber's status may become 'suspended' when the fiber function ends, instead of 'dead'.
Parameters:
is_joinable(boolean) — the boolean value that specifies whether the fiber is joinable
Returns
nil
Example:
See the fiber_object.join() example.
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().
timeout(number) — maximum number of seconds to wait for the completion of the fiber. Default: infinity.
Returns
none
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.
Return type
boolean + result type, or boolean + struct error
Possible errors: the fiber is already joined by concurrent
fiber:join().
Example:
The example below shows how to get the result returned by the fiber's function.
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)
The output should look as follows.
$ tarantool app.luaIs successful: trueReturned value: 11
Warning: yield() and any function which implicitly yields (such as sleep()) can fail (raise an exception).
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 doprint('before testcancel')fiber.testcancel()print('before yield')fiber.yield()endendfiber_object = fiber.create(function_name)fiber.sleep(.1)fiber_object:cancel()
Call fiber.channel() to create and get a new channel object.
Call the other routines, via channel, to send messages, receive messages, or check channel status.
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).
Create a new communication channel.
Parameters:
capacity(int) — the maximum number of slots (spaces forchannel:putmessages) that can be in use at once. The default is 0.
Returns
new channel object.
Return type
userdata. In the console output, it is serialized as channel: [number], where [number] is the return of [channel_object:count()](#channel_object-count).
method put(message[, timeout])
Send a message using a channel. If the channel is full, channel:put()
waits until there is a free slot in the channel.
-
message(lua-value) — what will be sent, usually a string or number or table -
timeout(number) — maximum number of seconds to wait for a slot to become free. Default: infinity.
Returns
If timeout is specified, and there is no free slot in the channel
for the duration of the timeout, then the return value is false.
If the channel is closed, then the return value is false.
Otherwise, the return value is true, indicating success.
Return type
boolean
Close the channel. All waiters in the channel will stop waiting. All
following channel:get() operations will return nil, and all
following channel:put() operations will return false.
Fetch and remove a message from a channel. If the channel is empty,
channel:get() waits for a message.
timeout(number) — maximum number of seconds to wait for a message. Default: infinity.
Returns
If timeout is specified, and there is no message in the channel for
the duration of the timeout, then the return value is nil. If the
channel is closed, then the return value is nil. Otherwise, the
return value is the message placed on the channel by
channel:put().
Return type
usually string or number or table, as determined by channel:put``
Check whether the channel is empty (has no messages).
Returns
true if the channel is empty. Otherwise false.
Return type
boolean
Find out how many messages are in the channel.
Returns
the number of messages.
Return type
number
Check whether the channel is full.
Returns
true if the channel is full (the number of messages in the channel
equals the number of slots so there is no room for a new message).
Otherwise false.
Return type
boolean
Check whether readers are waiting for a message because they have issued
channel:get() and the channel is empty.
Returns
true if readers are waiting. Otherwise false.
Return type
boolean
Check whether writers are waiting because they have issued
channel:put() and the channel is full.
Returns
true if writers are waiting. Otherwise false.
Return type
boolean
Returns
true if the channel is already closed. Otherwise false.
Return type
boolean
This example should give a rough idea of what some functions for fibers should look like. It's assumed that the functions would be referenced in fiber.create().
fiber = require('fiber')channel = fiber.channel(10)function consumer_fiber()while true dolocal task = channel:get()...endendfunction consumer2_fiber()while true do– 10 secondslocal task = channel:get(10)if task ~= nil then...else– timeoutendendendfunction producer_fiber()while true dotask = box.space...:select{...}...if channel:is_empty() then– channel is emptyendif channel:is_full() then– channel is fullend...if channel:has_readers() then– there are some fibers– that are waiting for dataend...if channel:has_writers() then– there are some fibers– that are waiting for readersendchannel:put(task)endendfunction producer2_fiber()while true dotask = box.space...select{...}– 10 secondsif channel:put(task, 10) then...else– timeoutendendend
Call fiber.cond() to create a named condition variable, which will be
called 'cond' for examples in this section.
Call cond:wait() to make a fiber wait for a signal via a condition
variable.
Call cond:signal() to send a signal to wake up a single fiber that has
executed cond:wait().
Call cond:broadcast() to send a signal to all fibers that have
executed cond:wait().
Create a new condition variable.
Returns
new condition variable.
Return type
Lua object
: cond_object
Make the current fiber go to sleep, waiting until another fiber invokes
the signal() or broadcast() method on the cond object. The sleep
causes an implicit fiber.yield().
Parameters:
timeout— number of seconds to wait, default = forever.
Returns
If timeout is provided, and a signal doesn't happen for the
duration of the timeout, wait() returns false. If a signal or
broadcast happens, wait() returns true.
Return type
boolean
Wake up a single fiber that has executed wait() for the same variable.
Does not yield.
Return type
nil
Wake up all fibers that have executed wait() for the same variable.
Does not yield.
Return type
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.
On terminal #1, say
$ tt connect localhost:3301tarantool> fiber = require('fiber')tarantool> cond = fiber.cond()tarantool> cond:wait()
The job will hang because cond:wait() -- without an optional timeout
argument -- will go to sleep until the condition variable changes.
On terminal #2, say
$ tt connect localhost:3301tarantool> cond:signal()
Now look again at terminal #1. It will show that the waiting stopped,
and the cond:wait() function returned true.
This example depended on the use of a global conditional variable with
the arbitrary name cond. In real life, programmers would make sure to
use different conditional variable names for different applications.