local utils = require "luacheck.utils" local multithreading = {} local lanes_ok, lanes = pcall(require, "lanes") lanes_ok = lanes_ok and pcall(lanes.configure) multithreading.has_lanes = lanes_ok multithreading.lanes = lanes multithreading.default_jobs = 1 if not lanes_ok then return multithreading end local cpu_number_detection_commands = {} if utils.is_windows then cpu_number_detection_commands[1] = "echo %NUMBER_OF_PROCESSORS%" else cpu_number_detection_commands[1] = "getconf _NPROCESSORS_ONLN 2>&1" cpu_number_detection_commands[2] = "sysctl -n hw.ncpu 2>&1" cpu_number_detection_commands[3] = "psrinfo -p 2>&1" end for _, command in ipairs(cpu_number_detection_commands) do local handler = io.popen(command) if handler then local output = handler:read("*a") handler:close() if output then local cpu_number = tonumber(utils.strip(output)) if cpu_number then multithreading.default_jobs = math.floor(math.max(cpu_number, 1)) break end end end end -- Reads pairs {key, arg} from given linda slot until it gets nil as arg. -- Returns table with pairs [key] = func(arg). local function worker_task(linda, input_slot, func) local results = {} while true do local _, pair = linda:receive(nil, input_slot) local key, arg = pair[1], pair[2] if arg == nil then return results end results[key] = func(arg) end end local function protected_worker_task(...) return true, utils.try(worker_task, ...) end local worker_gen = lanes.gen("*", protected_worker_task) -- Maps func over array, performing at most jobs calls in parallel. function multithreading.pmap(func, array, jobs) jobs = jobs or multithreading.default_jobs jobs = math.min(jobs, #array) if jobs < 2 then return utils.map(func, array) end local workers = {} local linda = lanes.linda() for i = 1, jobs do workers[i] = worker_gen(linda, 0, func) end for i, item in ipairs(array) do linda:send(nil, 0, {i, item}) end for _ = 1, jobs do linda:send(nil, 0, {}) end local results = {} for _, worker in ipairs(workers) do local _, ok, worker_results = assert(worker:join()) if ok then utils.update(results, worker_results) else error(worker_results, 0) end end return results end return multithreading