Skip to content

Instantly share code, notes, and snippets.

@duboisf
Last active April 1, 2025 16:29
Show Gist options
  • Save duboisf/8ec9b8666cfe5da8e1dd1ffb65331e8c to your computer and use it in GitHub Desktop.
Save duboisf/8ec9b8666cfe5da8e1dd1ffb65331e8c to your computer and use it in GitHub Desktop.
Example of running nvim coroutines sequentially and in parallel
-- Example of using coroutines with slow IO operations in Neovim.
-- It shows how to run coroutines sequentially and in "parallel".
-- The word "parallel" is in quotes because Lua coroutines are not actually
-- running in parallel, but the IO operations that they start are.
-- The coroutines are paused and resumed as the IO operations complete.
-- To run this example, put this file somewhere and do `:luafile path/to/coroutines.lua` in nvim.
local co = coroutine
vim.cmd "new"
Buf = vim.api.nvim_get_current_buf()
vim.bo.buftype = "nofile"
local function clear_buffer()
vim.api.nvim_buf_set_lines(Buf, 0, -1, false, {})
end
local function append_lines_to_buffer(buf, lines)
vim.api.nvim_buf_set_lines(buf, -1, -1, false, lines)
end
local function get_time()
-- Get time formatted as string
return os.date("%H:%M:%S")
end
---Log a message to the buffer.
---@param ... any
local function log(...)
local strings = vim.tbl_map(tostring, { ... })
local line = get_time() .. " " .. table.concat(strings, " ")
append_lines_to_buffer(Buf, { line })
end
clear_buffer()
vim.api.nvim_buf_set_lines(Buf, 0, -1, false, { get_time() .. " test.lua start" })
---@async
---Simulates slow IO by sleeping for a given number of milliseconds.
---@param delay number: The number of milliseconds to sleep for.
---@param result string: The result of the slow IO operation.
---@return string result The result of the slow IO operation.
local function simulate_slow_io(delay, result)
local thread = co.running()
assert(thread, "This function must be called inside a coroutine.")
vim.defer_fn(function()
log("resuming", thread)
co.resume(thread)
end, delay)
log("pausing", thread, "for", delay, "ms")
co.yield()
return result
end
local function parallel()
local thread = co.running()
assert(thread, "parallel() must be called inside a coroutine.")
local result1, result2, result3
co.wrap(function()
result1 = simulate_slow_io(3000, "parallel: slow io result1")
co.resume(thread)
end)()
co.wrap(function()
result2 = simulate_slow_io(1000, "parallel: slow io result2")
co.resume(thread)
end)()
co.wrap(function()
result3 = simulate_slow_io(5000, "parallel: slow io result3")
co.resume(thread)
end)()
-- yield 3 times as we started 3 coroutines that each yield once
-- when the slow IO operation is started and then resume the main coroutine
-- when the slow IO operation is done.
co.yield()
co.yield()
co.yield()
return result1, result2, result3
end
local function sequential()
local thread = co.running()
assert(thread, "sequential() must be called inside a coroutine.")
local result1, result2, result3
co.wrap(function()
result1 = simulate_slow_io(3000, "sequential: slow io result1")
result2 = simulate_slow_io(1000, "sequential: slow io result2")
result3 = simulate_slow_io(5000, "sequential: slow io result3")
co.resume(thread)
end)()
co.yield()
return result1, result2, result3
end
co.wrap(function()
local start_time = os.time()
log("Runnning sequentially")
local r1, r2, r3 = sequential()
local total_time = os.time() - start_time
log("sequential: total time: ", total_time, "seconds, results:", r1, r2, r3)
start_time = os.time()
log("Runnning in parallel")
r1, r2, r3 = parallel()
total_time = os.time() - start_time
log("parallel: total time", total_time, "seconds, results", r1, r2, r3)
log("test.lua end")
end)()
-- output should look like this:
-- 12:21:35 test.lua start
-- 12:21:35 Runnning sequentially
-- 12:21:35 pausing thread: 0x75db2de6ad78 for 3000 ms
-- 12:21:38 resuming thread: 0x75db2de6ad78
-- 12:21:38 pausing thread: 0x75db2de6ad78 for 1000 ms
-- 12:21:39 resuming thread: 0x75db2de6ad78
-- 12:21:39 pausing thread: 0x75db2de6ad78 for 5000 ms
-- 12:21:44 resuming thread: 0x75db2de6ad78
-- 12:21:44 sequential: total time: 9 seconds, results: sequential: slow io result1 sequential: slow io result2 sequential: slow io result3
-- 12:21:44 Runnning in parallel
-- 12:21:44 pausing thread: 0x75db2ce46520 for 3000 ms
-- 12:21:44 pausing thread: 0x75db2e312840 for 1000 ms
-- 12:21:44 pausing thread: 0x75db2d26e5e0 for 5000 ms
-- 12:21:45 resuming thread: 0x75db2e312840
-- 12:21:47 resuming thread: 0x75db2ce46520
-- 12:21:49 resuming thread: 0x75db2d26e5e0
-- 12:21:49 parallel: total time 5 seconds, results parallel: slow io result1 parallel: slow io result2 parallel: slow io result3
-- 12:21:49 test.lua end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment