利用LUA协程实现FUTURE模式
1. Future模式:
参见 http://www.cnblogs.com/zhiranok/archive/2011/03/26/Future_Pattern.html
使用future的好处是即利用了异步的并行能力,又保证主逻辑串行执行,保持简单。
2. Lua 协程
sina Timyang 的介绍 http://timyang.net/lua/lua-coroutine/
lua coroutine 通过create创建一个伪线程,该“线程”通过yield可以挂起自己,通过调用resume可以使该“线程”从挂起位置继续执行。
3. LUA coroutine 实现 Future
假设有如下应用场景:
1. 用户登录系统,需要将用户数据从Mysql中获取用户数据,然后在LUA中实例化user_t对象。
2. 用户登录事件由C++触发,将uid参数传递给lua
3. lua 并不存在mysql接口,必须委托c++完成mysql操作,而且lua state必须被单线程操作,顾我们期望LUA不能被阻塞,在单个user从mysql 载入数据
时其他user应该能够继续接受请求
故我们设计了如下解决方案:
1. lua中的user_t对象每个实例拥有两个主要数据,
a. request_cache,在user未初始化完成时该uid的请求将被缓存起来(我们将请求封装成function)。
b. coroutine ,该协程尝试将request_cache中的所有请求执行完毕,当出现如下情况该协程为挂起自己
(1)request_cache 为空,挂起等待新的请求
(2)需要执行mysql时挂起,等待mysql执行完毕被唤醒。
示例代码:
1 user_t = {}
2 user_t.__index = user_t
3
4 function user_t:new()
5 local funjc = function() print("TODO exe all request in request_cache") end
6 local ret =
7 {
8 ["request_cache"] = {},
9 ["coroutine_obj"] = coroutine.create(funjc),
10 }
11 setmetatable(ret, self)
12 return ret
13 end
2. C++ 封装异步调用Mysql的接口,注册接口到LUA
1. future_t 用于LUA和C++传递数据
1 class future_t
2 {
3 public:
2. async_load_data_from_db 用于异步执行mysql操作
1 void async_load_data_from_db(future_t* ret_)
2 {
3 //! post another thread, async exe load data from db
4 thread.post(boost::bind(do_load_data_from_db, ret_));
5 }
6
7 void do_load_data_from_db(future_t* ret_)
8 {
9 //! TODO exe sql opertion
10 lua_pcall("resume_routine")
11 }
lua 调用C++的接口async_load_data_from_db,async_load_data_from_db 将请求post另外的线程,执行mysql请求,将请求结果赋值到future中,调用lua的resume函数唤醒
lua协程继续执行
3. LUA 示例代码
1 user_t = {}
2 user_t.__index = user_t
3
4 function user_t:new(uid_)
5 local ret =
6 {
7 ["uid"] = uid_,
8 ["request_cache"] = {},
9 ["coroutine_obj"] = true,
10 ["runing_flag"] = true,
11 }
12 setmetatable(ret, self)
13
14 local func = function()
15 while true == runing_flag
16 if 0 == #ret.request_cache
17 then
18 coroutine.yield()
19 else
20 local todo_func = ret.request_cache[1]
21 local tmp = {}
22 for k = 2, #ret.request_cache
23 do
24 table.insert(tmp, ret.request_cache[k])
25 end
26 ret.request_cache = tmp
27 todo_func()
28 end
29 end
30 end
31 ret.coroutine_obj = coroutine.create(func)
32 return ret
33 end
34
35 function user_t:init()
36 local func = function()
37 local future = future_t:new()
38 async_load_data_from_db(future)
39 coroutine.yield()
40 print("user_t:init ok", self.uid, future:get_result())
41 future:delete()
42 end
43 table.insert(self.request_cache, func)
44 coroutine.resume(self.coroutine_obj)
45 end
46
47 function user_t:resume_routine()
48 coroutine.resume(self.coroutine_obj)
49 end
50
51 local test_user = user_t:new(1122334)
52
53 function user_login()
54 return test_user:init()
55 end
56
57 function resume_routine()
58 return test_user:resume_routine()
59 end
4. 注意事项:
尽管一个lua state是串行执行的,使用lua coroutine时仍然要注意数据一致性,比如在coroutine执行时使用了全局变量,yield挂起后全局变量有可能被修改了,
所以协程适合于例子中的user_t对象,各个user是互不干扰的,相同的user请求会被单个协程串行化。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP模型Model类封装数据库操作示例
- 解决django migrate报错ORA-02000: missing ALWAYS keyword
- PHP封装的数据库模型Model类完整示例【基于PDO】
- PHP的简单跳转提示的实现详解
- PHP多进程通信-消息队列使用
- PHP implode()函数用法讲解
- PHP精确到毫秒秒杀倒计时实例详解
- django 装饰器 检测登录状态操作
- 使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
- Django Session和Cookie分别实现记住用户登录状态操作
- 使用PHPUnit进行单元测试并生成代码覆盖率报告的方法
- PHP封装XML和JSON格式数据接口操作示例
- 浅谈PHP进程管理
- php使用fullcalendar日历插件详解
- PHP htmlspecialchars()函数用法与实例讲解