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

原文地址:https://www.cnblogs.com/cutepig/p/11055612.html

时间: 2024-10-10 16:47:38

lua:写了个基于协程的task调度库的相关文章

基于协程的Python网络库gevent

import gevent def test1(): print 12 gevent.sleep(0) print 34 def test2(): print 56 gevent.sleep(0) print 78 gevent.joinall([ gevent.spawn(test1), gevent.spawn(test2), ]) 解释下,"gevent.spawn()"方法会创建一个新的greenlet协程对象,并运行它."gevent.joinall()"

Python实现基于协程的异步爬虫

一.课程介绍 1. 课程来源 本课程核心部分来自<500 lines or less>项目,作者是来自 MongoDB 的工程师 A. Jesse Jiryu Davis 与 Python 之父 Guido van Rossum.项目代码使用 MIT 协议,项目文档使用 http://creativecommons.org/licenses/by/3.0/legalcode 协议. 课程内容在原文档基础上做了稍许修改,增加了部分原理介绍,步骤的拆解分析及源代码注释. 2. 内容简介 传统计算机

基于协程的爬虫

基于gevent(协程),抓取站点的所有url 说到协程,协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用. 协程在执行过程中遇到阻塞时转而执行别的子程序,阻塞结束后再返回来接着执行. 在gevent里面,上下文切换是通过yielding来完成的 代码中用到requests,xpath 如果有不懂xpath的小伙伴 --> 传送门 requests不理解的小伙伴 -->传送门 monkey.patch_all()用来在运行时动态修改已有的代码,而不需要修改原始代码官方文

lua学习笔记13:协程具体解释和举例

一.coroutine.create创建协程 參数是协程的主函数,返回一个thread对象 co = coroutine.create(function() print("coroutine execute!") end) 二.协程状态 协程有三种状态:挂起(suspended).执行(running)和死亡(dead) coroutine.status(co)返回协程当前的状态 协程创建完之后处于挂起状态 print(coroutine.status(co)) 输出: suspend

在PHP中使用协程实现多任务调度

PHP5.5一个比较好的新功能是加入了对迭代生成器和协程的支持.对于生成器,PHP的文档和各种其他的博客文章已经有了非常详细的讲解.协程相对受到的关注就少了,因为协程虽然有很强大的功能但相对比较复杂, 也比较难被理解,解释起来也比较困难. 这篇文章将尝试通过介绍如何使用协程来实施任务调度, 来解释在PHP中的协程. 我将在前三节做一个简单的背景介绍.如果你已经有了比较好的基础,可以直接跳到“协同多任务处理”一节. 迭代生成器 生成器也是一个函数,不同的是这个函数的返回值是依次输出,而不是只返回一

[lua]异步串行流程*协程

local function param_pack( params, callback ) local host = params[1] local service = table.remove(params, 2) table.insert(params, callback) return host, service, params end local function asyncall( ... ) local co, main = coroutine.running() if main t

单线程实现并发——协程,gevent模块

一 并发的本质 1 切换 2 保存状态 二 协程的概念 协程,又称微线程,纤程.英文名Coroutine.单线程下实现并发,用户从应用程序级别控制单线程下任务的切换,注意一定是遇到I/O才切. 协程的特点在于是一个线程执行,那和多线程比,协程有何优势? 最大的优势就是协程极高的执行效率.因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显. 第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中

并发编程协程(Coroutine)之Gevent

Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译为协同的例程,一般我们都简称为协程. 在linux系统中,线程就是轻量级的进程,而我们通常也把协程称为轻量级的线程即微线程. 进程和协程 下面对比一下进程和协程的相同点和不同点: 相同点:我们都可以把他们看做是一种执行流,执行流可以挂起,并且后面可以在你挂起的地方恢复执行,这实际上都可以看做是con

Lua-Async 协程的高级用法

Lua-Async 这是一个基于协程的异步调用库, 该库的设计思路类似JavaScript的Promise, 但相比Promise, 它有更多的灵活性. -- 引入Async local Async = require("Async") -- 创建Async -- 可传递参数到接下来的调用中 Async.New(...) -- 注册异步调用 Async.New(...) :Ok(function(ok, no, ...) return no() end) -- 在Ok管道注册回调, 之