Skip to content

Instantly share code, notes, and snippets.

@kurapica
Created July 19, 2021 01:58
Show Gist options
  • Save kurapica/8d85ff8bdeb989d6d5fd18a638a0e768 to your computer and use it in GitHub Desktop.
Save kurapica/8d85ff8bdeb989d6d5fd18a638a0e768 to your computer and use it in GitHub Desktop.
Full thread pool support func and iterator
local create = coroutine.create
local resume = coroutine.resume
local running = coroutine.running
local status = coroutine.status
local wrap = coroutine.wrap
local yield = coroutine.yield
local tinsert = table.insert
local tremove = table.remove
local loadstring = loadstring
local select = select
local tblconcat = table.concat
local strformat = string.format
local PREPARE_CONFIRM = {}
local _PassArgs = { [0] = function(thread, func) return func(yield(thread)) end }
local _PassGenCode = [[local yield = ... return function (thread, func, %s) return func(%s, yield(thread)) end]]
local _ThreadPool = {}
local function newPass(count)
local args = {}
for i = 1, count do args[i] = "arg" .. i end
args = tblconcat(args, ", ")
local pass = loadstring(strformat(_PassGenCode, args, args))(yield)
_PassArgs[count] = pass
return pass
end
local function returnwithrecycle(thread, asiter, ...)
if #_ThreadPool < 100 then tinsert(_ThreadPool, thread) end -- recyle the thread
if asiter then
if select("#", ...) > 0 then yield(...) end -- return the value
yield() -- make sure the iterator don't resume again
yield()
else
yield(...)
end
end
local function preparefunc(thread, func, asiter, ...)
if not func then return end
local cnt = select("#", ...)
returnwithrecycle(thread, asiter, (_PassArgs[cnt] or newPass(cnt))(thread, func, ...))
end
local function recyclethread(thread)
while true do preparefunc(thread, yield(PREPARE_CONFIRM)) end
end
local function newrecyclethread()
local thread = tremove(_ThreadPool)
-- Check Re-usable
if thread then for i = 1, 3 do if thread() == PREPARE_CONFIRM then return thread end end end
-- Create the new thread
thread = wrap(recyclethread)
thread(thread) -- pass the pool and thread to be recycled
return thread
end
function ThreadCall(func, ...)
local thread = newrecyclethread()
return thread(func)(...)
end
function GetIterator(func, ...)
local thread = newrecyclethread()
return thread(func, true, ...)
end
ThreadCall(function() print(coroutine.running()) end)
ThreadCall(function() print(coroutine.running()) end)
ThreadCall(function() print(coroutine.running()) end)
function iter(s, t)
for i = s, t do
yield(i, i^2)
end
end
-- You can pass the arguments in or outside the call
for i, v in GetIterator(iter, 1, 10) do
print(i, v)
end
print("---------------------------")
for i, v in GetIterator(iter), 1, 10 do
print(i, v)
end
print("---------------------------")
for i, v in GetIterator(iter, 1), 10 do
print(i, v)
end
@kurapica
Copy link
Author

The result should be in Lua5.1 and LuaJIT, for upper version, should use load instead of the loadstring

thread: 00B486F0
thread: 00B486F0
thread: 00B486F0
1	1
2	4
3	9
4	16
5	25
6	36
7	49
8	64
9	81
10	100
---------------------------
1	1
2	4
3	9
4	16
5	25
6	36
7	49
8	64
9	81
10	100
---------------------------
1	1
2	4
3	9
4	16
5	25
6	36
7	49
8	64
9	81
10	100

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment