參見http://www.cnblogs.com/zhiranok/archive/2011/03/26/Future_Pattern.htmlhtml
使用future的好處是即利用了異步的並行能力,又保證主邏輯串行執行,保持簡單。mysql
sina Timyang 的介紹 http://timyang.net/lua/lua-coroutine/c++
lua coroutine 經過create建立一個僞線程,該「線程」經過yield能夠掛起本身,經過調用resume可使該「線程」從掛起位置繼續執行。sql
假設有以下應用場景:緩存
1. 用戶登陸系統,須要將用戶數據從Mysql中獲取用戶數據,而後在Lua中實例化user_t對象。異步
2. 用戶登陸事件由C++觸發,將uid參數傳遞給luaasync
3. lua 並不存在mysql接口,必須委託c++完成mysql操做,並且Lua state必須被單線程操做,故咱們指望Lua不能被阻塞,在單個user從mysql 載入數據時其餘user應該可以繼續接受請求函數
咱們設計了以下解決方案:post
a. request_cache,在user未初始化完成時該uid的請求將被緩存起來(咱們將請求封裝成function)。ui
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
1. future_t 用於LUA和C++傳遞數據
1 class future_t 2 { 3 public:
void set_result(const string& v_) { m_result = v_; } 4 string get_result() const { return m_result; } 5 private: 6 string m_result; 7 };
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協程繼續執行
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 do 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
儘管一個Lua state是串行執行的,使用Lua coroutine時仍然要注意數據一致性,好比在coroutine執行時使用了全局變量,yield掛起後全局變量有可能被修改了,
因此協程適合於例子中的user_t對象,各個user是互不干擾的,相同的user請求會被單個協程串行化。