lua:写了个基于协程的task调度库

写了一个(不完整的)基于协程的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

 

posted on 2019-06-19 23:09  cutepig  阅读(773)  评论(0编辑  收藏  举报

导航