基于lua协程的AI服务实现
2012-04-02 09:40
337 查看
以前写过一编博客介绍我们游戏的AI服务器。
基本的结构就是利用windows的fiber,在每个fiber中运行一个lua虚拟机,具体的内容可以产参看
http://blog.csdn.net/sniperhuangwei/article/details/5425471
但这个方案有一个缺点,就是随着项目的推移,AI脚本变得越来越复杂,每个虚拟机占用的内存就变得越来越大。
当一个进程上运行的AI对象数量很大时这个进程就吃掉了非常大的内存。
经过一番考量,我决定不使用windows的fiber来支持用户态线程调度框架,而是改用lua的coroutine.
这样整个进程只需要维护一个lua虚拟机就够了,即使AI脚本变得更复杂所占用的内存也不会太恐怖.
下面是coroutine的调度框架,基本结构跟原来的fiber框架是一样的.
co.lua
timer.lua
scheduler.lua
test.lua
基本的结构就是利用windows的fiber,在每个fiber中运行一个lua虚拟机,具体的内容可以产参看
http://blog.csdn.net/sniperhuangwei/article/details/5425471
但这个方案有一个缺点,就是随着项目的推移,AI脚本变得越来越复杂,每个虚拟机占用的内存就变得越来越大。
当一个进程上运行的AI对象数量很大时这个进程就吃掉了非常大的内存。
经过一番考量,我决定不使用windows的fiber来支持用户态线程调度框架,而是改用lua的coroutine.
这样整个进程只需要维护一个lua虚拟机就够了,即使AI脚本变得更复杂所占用的内存也不会太恐怖.
下面是coroutine的调度框架,基本结构跟原来的fiber框架是一样的.
co.lua
coObject = { next_co = nil, --活动队列中的下一个协程对象 co = nil, --协程对象 status, --当前的状态 block = nil, --阻塞结构 timeout, index = 0, sc, --归属的调度器 name } function coObject:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end function coObject:init(name,sc,co) self.name = name self.sc = sc self.co = co end function coObject:Signal(ev) if self.block ~= nil then if self.block:WakeUp(ev) then self.sc:Add2Active(self) end end end blockStruct = { bs_type, } function blockStruct:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end function blockStruct:WakeUp(type) return true end
timer.lua
timer = { m_size = 0, --元素的数量 m_data = {} --元素 } function timer:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end function timer:Up(index) local parent_idx = self:Parent(index) while parent_idx > 0 do if self.m_data[index].timeout < self.m_data[parent_idx].timeout then self:swap(index,parent_idx) index = parent_idx parent_idx = self:Parent(index) else break end end end function timer:Down(index) local l = self:Left(index) local r = self:Right(index) local min = index if l <= self.m_size and self.m_data[l].timeout < self.m_data[index].timeout then min = l end if r <= self.m_size and self.m_data[r].timeout < self.m_data[min].timeout then min = r end if min ~= index then self:swap(index,min) self:Down(min) end end function timer:Parent(index) return index/2 end function timer:Left(index) return 2*index end function timer:Right(index) return 2*index + 1 end function timer:Change(co) local index = co.index if index == 0 then return end --尝试往下调整 self:Down(index) --尝试往上调整 self:Up(index) end function timer:Insert(co) if co.index ~= 0 then return end self.m_size = self.m_size + 1 table.insert(self.m_data,co) co.index = self.m_size self:Up(self.m_size) end function timer:Min() if self.m_size == 0 then return 0 end return self.m_data[1].timeout end function timer:PopMin() local co = self.m_data[1] self:swap(1,self.m_size) self.m_data[self.m_size] = nil self.m_size = self.m_size - 1 self:Down(1) co.index = 0 return co end function timer:Size() return self.m_size end function timer:swap(idx1,idx2) local tmp = self.m_data[idx1] self.m_data[idx1] = self.m_data[idx2] self.m_data[idx2] = tmp self.m_data[idx1].index = idx1 self.m_data[idx2].index = idx2 end function timer:Clear() while m_size > 0 do self:PopMin() end self.m_size = 0 end
scheduler.lua
scheduler = { active_head = nil,--活动列表头 active_tail = nil,--活动列表尾 pending_add = {},--等待添加到活动列表中的coObject m_timer = nil, } function scheduler:new(o) o = o or {} setmetatable(o, self) self.__index = self return o end function scheduler:init() self.m_timer = timer:new() end --添加到活动列表中 function scheduler:Add2Active(coObj) table.insert(self.pending_add,coObj) end --尝试唤醒uid function scheduler:TryWakeup(coObj,ev) if coObj.block then coObj:Signal(ev) end end --强制唤醒纤程 function scheduler:ForceWakeup(coObj) if coObj.status ~= "ACTIVED" then coObj.sc:Add2Active(coObj) end end --强制唤醒阻塞在type条件上的纤程 function scheduler:ForceWakeup(coObj,type) if coObj.status ~= "ACTIVED" and coObj.block and coObj.block.bs_type == type then coObj.sc:Add2Active(coObj) end end --睡眠ms function scheduler:Sleep(coObj,ms) if ms > 0 then coObj.timeout = GetTick() + ms if coObj.index == 0 then self.m_timer:Insert(coObj) else self.m_timer:Change(coObj) end coObj.status = "SLEEP" end coroutine.yield(coObj.co) end --暂时释放执行权 function scheduler:Yield(coObj) coObj.status = "YIELD" coroutine.yield(coObj.co) end --主调度循环 function scheduler:Schedule() --将pending_add中所有coObject添加到活动列表中 for k,v in pairs(self.pending_add) do v.next_co = nil if self.active_tail ~= nil then self.active_tail.next_co = v self.active_tail = v else self.active_head = v self.active_tail = v end end self.pending_add = {} --运行所有可运行的coObject对象 local cur = self.active_head local pre = nil while cur ~= nil do coroutine.resume(cur.co,cur) print("从coro中回来") local status = cur.status --当纤程处于以下状态时需要从可运行队列中移除 if status == "DEAD" or status == "SLEEP" or status == "WAIT4EVENT" or status == "YIELD" then --删除首元素 if cur == self.active_head then --同时也是尾元素 if cur == self.active_tail then self.active_head = nil self.active_tail = nil else self.active_head = cur.next_co end elseif cur == self.active_tail then pre.next_co = nil self.active_tail = pre else pre.next_co = cur.next_co end local tmp = cur cur = cur.next_co tmp.next_co = nil --如果仅仅是让出处理器,需要重新投入到可运行队列中 if status == "YIELD" then self:Add2Active(tmp) end else pre = cur cur = cur.next_co end end --看看有没有timeout的纤程 local now = GetTick() while self.m_timer:Min() ~=0 and self.m_timer:Min() <= now do local co = self.m_timer:PopMin() if co.status == "WAIT4EVENT" or co.status == "SLEEP" then self:Add2Active(co) end end end
test.lua
function cofun(coObj) while true do Show() print(coObj.name) coObj.sc:Sleep(coObj,1) end end function test() local sc = scheduler:new() sc:init() local co1 = coObject:new() local coro1 = coroutine.create(cofun) co1:init("1",sc,coro1) local co2 = coObject:new() local coro2 = coroutine.create(cofun) co2:init("2",sc,coro2) local co3 = coObject:new() local coro3 = coroutine.create(cofun) co3:init("3",sc,coro3) local co4 = coObject:new() local coro4 = coroutine.create(cofun) co4:init("4",sc,coro4) sc:Add2Active(co1) sc:Add2Active(co2) sc:Add2Active(co3) sc:Add2Active(co4) while true do sc:Schedule() end end
相关文章推荐
- 基于 lua-resty-upload 实现简单的文件上传服务
- 基于 lua-resty-upload 实现简单的文件上传服务
- 基于Spring Boot和Spring Cloud实现微服务架构学习--转
- 基于visual c++之windows核心编程代码分析(66)实现Windows服务的远程控制
- [ZooKeeper.net] 1 模仿dubbo实现一个简要的http服务的注册 基于webapi
- TopShelf+Quartz.net实现基于window服务的定时调度
- 基于RHCS+iSCSI+CLVM实现Web服务的共享存储集群架构
- 基于casperjs和resemble.js实现一个像素对比服务详解
- 【Dubbo实战】 Dubbo+Zookeeper+Spring整合应用篇-Dubbo基于Zookeeper实现分布式服务
- Apache服务器实现基于名称的虚拟主机服务 推荐
- 基于tensorflow实现AI图片鉴黄(NSFW)
- 基于 IdentityServer3 实现 OAuth 2.0 授权服务数据持久化
- 构建基于CXF的WebService服务(3)-- 利用拦截器实现权限验证
- Python实现基于协程的异步爬虫
- 基于guice、resteasy、mybatis和undertow实现的轻量级restful服务
- 实验:基于keepalived实现两台realserver服务器中的nginx和php-fpm服务互为主从
- 使用TensorFlow基于阿里云AI实现图像识别技术(HR)
- 基于Redis实现延时队列服务
- 基于spring-cloud实现eureka注册服务小案例
- 基于C++实现五子棋AI算法思想