写了一个(不完整的)基于协程的task调度库
sample code如下
my_spawn( function () print('f: 1') local t1 = my_spawn( function () print('f: 3') task_yield_to_be_schedule() print('f: 4') end ) --task_yield_to_be_schedule() my_wait_task(t1) print('f: 2') end ) local num_run = 0 while my_run_once() do dbgprint('>>exec ', num_run) num_run = num_run + 1 end
features
- 支持spwan
- 支持在task里面spawn
- 支持task里面yield
- 支持task里面等待其他task
todo
- 支持在task里面sleep
- 支持在task里面设置和等待event
完整源代码如下
require('mobdebug').coro() local inspect = require('inspect') local debug_on = true local function dbgprint(...) if debug_on then print(...) end end if false then function f() print('in f') coroutine.yield(100) print('in f2') end local task1 = coroutine.create(f) print(coroutine.status(task1)) local ret, r2, r3 = coroutine.resume(task1) print(ret) print(coroutine.status(task1)) print(coroutine.resume(task1)) print(coroutine.resume(task1)) print(coroutine.status(task1)) return end -- scheduler -- lowlevel support: spawn, wait, events and timeout -- to be run tasks local tasks_to_be_scheduled = {} -- to be timeout tasks local tasks_to_be_timeout = {} -- to be set event tasks local tasks_to_be_event = {} -- to be waited tasks, this is a map where key is task handle, value is the tasks waiting this task local tasks_to_be_wait = {} -- task yield flags local yield_flag_to_be_schedule = 1 local yield_flag_timeout = 2 local yield_flag_event = 3 local yield_flag_wait_task = 3 function my_spawn(f) local t = coroutine.create(f) table.insert(tasks_to_be_scheduled, t) return t end function my_run_once() -- loop to be scueduled tasks if #tasks_to_be_scheduled > 0 then -- fetch a task local t = table.remove(tasks_to_be_scheduled, 1) assert(coroutine.status(t)=="suspended") -- exec local ret, data1, data2 = coroutine.resume(t) dbgprint ('>>resume coroutine returns ', ret, inspect(data1), data2) assert(ret) -- handle following if coroutine.status(t) ~= 'dead' then assert(data1 and data1.yield_flag) local dispatch={} dispatch[yield_flag_to_be_schedule] = function () table.insert(tasks_to_be_scheduled, t) end dispatch[yield_flag_wait_task] = function () end local disp = dispatch[data1.yield_flag] if disp then disp() else assert(0) end else -- loop to see who are waiting this task? local tasks_to_be_schedule = tasks_to_be_wait[t] if tasks_to_be_schedule then dbgprint ('>>trigger depent tasks ', inspect(tasks_to_be_schedule)) for i, task_to_be_schedule in ipairs(tasks_to_be_schedule) do table.insert(tasks_to_be_scheduled, task_to_be_schedule) end tasks_to_be_wait[t] = nil end end return true end return false end function task_yield_to_be_schedule() coroutine.yield ({yield_flag=yield_flag_to_be_schedule}) end function my_wait_task(t) -- when t done, need notify this_task local this_task = coroutine.running() if not tasks_to_be_wait[this_task] then tasks_to_be_wait[t] = {this_task} else table.insert(tasks_to_be_wait[t], this_task) end -- yield from current task coroutine.yield ({yield_flag=yield_flag_wait_task, handle=t}) end my_spawn( function () print('f: 1') local t1 = my_spawn( function () print('f: 3') task_yield_to_be_schedule() print('f: 4') end ) --task_yield_to_be_schedule() my_wait_task(t1) print('f: 2') end ) local num_run = 0 while my_run_once() do dbgprint('>>exec ', num_run) num_run = num_run + 1 end