Most of the Gio facilities are supported natively through
gobject-introspection layer. However, lgi provides Gio.Async
which
help in using Gio-style asynchronous I/O operations.
Native Gio asynchronous operations are based on traditional callback scheme, i.e. the operation is started, pushed to be performed on the background and when it finishes, it calls registered callback with operation results as arguments. While this scheme is widely used for asynchronous programming, it leads to spaghetti code full of callbacks. Lua provides coroutines, which can be used to make the code look 'synchronous' again, but still retaining the advantage of non-blocking I/O operations.
Gio-style asynchronous functions come as pair of two methods;
name_async
which starts operation and registers callback, and
name_finish
, which should be called in the context of registered
callback and allows retrieveing operation results. When Gio
override is loaded, lgi detects any of these pairs (in any object, not
just from Gio namespace) and when found, it synthesizes async_name
operations, which wraps native methods and uses Lua coroutines to
convert callbacks into synchronous code. In order for async_method
to work, these methods have to be called in the context of functions
called through Gio.Async
spawning facilities; either
Gio.Async.call
for synchronous calls and Gio.Async.start
for
starting routine on background.
This helper class implemented by lgi (not originating from introspected Gio module) contains interface for using lgi asynchronous support. This class contains only static methods and attributes, it is not possible to instantiate it.
local call_results = Gio.Async.call(user_function[, cancellable[, io_priority])(user_args)
local resume_results = Gio.Async.start(user_function[, cancellable[, io_priority])(user_args)
These methods accept user function to be run as argument and return function which starts execution of the user function in async-enabled context.
Any async_name
methods called inside context do not accept
io_priority
and cancellable
arguments (as their name_async
original counterparts do), instead global cancellable and io_priority
values given as arguments to Gio.Async.call/start
are used.
Code running inside async-enabled context can query or change value of
context-default cancellable
and io_priority
attributes by getting
or setting them as attributes of Gio.Async
class.
If cancellable
or io_priority
arguments are not provided to
Gio.Async.start
or Gio.Async.call
, they are automatically
inherited from currently running async-enabled coroutine, or default
values are used (if caller is not running in async-enabled context).
Following example reacts on the press of button, reads contents of
/etc/passwd
and dumps it to standard output.
local window = Gtk.Window {
... Gtk.Button { id = 'button', label = 'Breach' }, ...
}
function window.child.button:on_clicked()
local function dump_file(filename)
local file = Gio.File.new_for_path(filename)
local info = file:async_query_info('standard::size', 'NONE')
local stream = file:async_read()
local bytes = stream:async_read_bytes(info:get_size())
print(bytes.data)
stream:async_close()
end
Gio.Async.start(dump_file)('/etc/passwd')
end
Note that all reading happens running on background, on_clicked() handler finished when the operation is still running on background, so if you have a few gigabytes worth /etc/passwd file, the application will not freeze while dumping it.
samples/giostream.lua
provides far more involved sample illustrating
use of asynchronous operations.