lgi-devs / lgi

Dynamic Lua binding to GObject libraries using GObject-Introspection
MIT License
440 stars 70 forks source link

Suggestion: add `runPool` functionality to lgi #240

Open v1993 opened 4 years ago

v1993 commented 4 years ago

I often use lgi inside various very linear scripts where idea of main loop is plain unacceptable. However, today I ran into problem: I need to run few actions in parallel, while keeping overall flow of script linear.

Here's my solution together with a simple test:

local lgi = require 'lgi'
local Gio = lgi.Gio

-- Run taskcnt instances of func as async tasks and wait until all
-- of them finish. Function is called with task ID and
-- additional arguments you passed to this call.

local function runPool(func, taskcnt, ...)
    local args = {...}
    local result, err = true
    local app = Gio.Application.new(nil, {})

    -- Use protected call for proper error handling
    local function runner(...)
        local r, e = xpcall(func, debug.traceback, ...)

        -- Report first error
        if not r and result then
            result, err = r, e
        end

        app:release()
    end

    function app:on_activate()
        for i=1, taskcnt do
            app:hold()
            Gio.Async.start(runner)(i, table.unpack(args))
        end
    end

    app:run()

    return result, err
end

local function doTest(round)
    assert(runPool(function(number, arg)
        local len = math.random(1, 6)
        print(('Waiting %d seconds in thread %d (round %d)'):format(len, number, arg))
        local proc = assert(Gio.Subprocess.new({'sleep', len}, 'NONE'))
        proc:async_wait()
        print(('Finished waiting %d seconds in thread %d (round %d)'):format(len, number, arg))
    end, 4, round))
end

for i=1,3 do
    print(('Testing round %d start'):format(i))
    doTest(i)
    print(('Testing round %d end'):format(i))
end

runPool seems VERY useful for anyone wanting to add parallelism into their scripts using lgi. I suggest integrating it into lgi possibly as Gio.Async.pool.

Known limitations: