perf: prevent active waiting in coroutines. suspend/resume instead

This commit is contained in:
Folke Lemaitre 2024-06-27 13:06:39 +02:00
parent 79bcc02d17
commit 68cee30cdb
No known key found for this signature in database
GPG Key ID: 41F8B1FBACAE2040
3 changed files with 35 additions and 11 deletions

View File

@ -9,10 +9,14 @@ local M = {}
M._queue = {} M._queue = {}
M._executor = assert(vim.loop.new_check()) M._executor = assert(vim.loop.new_check())
M._running = false M._running = false
M.SLEEP = "sleep"
---@type Async
M.current = nil
---@class Async ---@class Async
---@field co thread ---@field co thread
---@field opts AsyncOpts ---@field opts AsyncOpts
---@field sleeping? boolean
local Async = {} local Async = {}
---@param fn async fun() ---@param fn async fun()
@ -29,16 +33,38 @@ function Async:running()
return coroutine.status(self.co) ~= "dead" return coroutine.status(self.co) ~= "dead"
end end
function Async:sleep(ms)
self.sleeping = true
vim.defer_fn(function()
self.sleeping = false
end, ms)
end
function Async:suspend()
self.sleeping = true
end
function Async:resume()
self.sleeping = false
end
function Async:step() function Async:step()
if self.sleeping then
return true
end
local status = coroutine.status(self.co) local status = coroutine.status(self.co)
if status == "suspended" then if status == "suspended" then
M.current = self
local ok, res = coroutine.resume(self.co) local ok, res = coroutine.resume(self.co)
M.current = nil
if not ok then if not ok then
if self.opts.on_error then if self.opts.on_error then
self.opts.on_error(tostring(res)) self.opts.on_error(tostring(res))
end end
elseif res then elseif res then
if self.opts.on_yield then if res == M.SLEEP then
self.sleeping = true
elseif self.opts.on_yield then
self.opts.on_yield(res) self.opts.on_yield(res)
end end
end end

View File

@ -222,6 +222,8 @@ function Task:spawn(cmd, opts)
end end
end end
self._running:suspend()
local running = true local running = true
local ret = true local ret = true
---@param output string ---@param output string
@ -234,6 +236,7 @@ function Task:spawn(cmd, opts)
end end
ret = ok ret = ok
running = false running = false
self._running:resume()
end end
if headless then if headless then
@ -244,9 +247,8 @@ function Task:spawn(cmd, opts)
end end
end end
Process.spawn(cmd, opts) Process.spawn(cmd, opts)
while running do
coroutine.yield() coroutine.yield()
end assert(not running, "process still running?")
return ret return ret
end end

View File

@ -232,13 +232,9 @@ end
---@async ---@async
---@param ms number ---@param ms number
function M.sleep(ms) function M.sleep(ms)
local continue = false local async = require("lazy.async").current
vim.defer_fn(function() assert(async, "Not in an async context")
continue = true async:sleep(ms)
end, ms)
while not continue do
coroutine.yield()
end
end end
function M._dump(value, result) function M._dump(value, result)