- 对于关键流程,所有请求都要求返回有效结果,如创建socket连接:
function luasocket:connect()
return socketcore.open(self.__host, self.__port)
end
显然外部调用需要获取到正确的socket句柄用于数据交互,当并发调用此接口时,所有调用都需要获取到有效的句柄以保证业务正常;
方案:加锁,保证临界区只由唯一的coroutine正确执行,并发的其他coroutine在临界区处休眠等待,临界区执行完成后,负责唤醒所有休眠的coroutine,直接获取有效结果返回;
function luasocket:safe_connect()
local conn
local nwaitingco = #self.__connecting -- wait queue
if nwaitingco > 0 then
-- connecting in other coroutine
local co = coroutine.running()
table.insert(self.__connecting, co)
skynet.wait(co)
return assert(conn) -- return conn when being awakened
end
-- the effective coroutine which build connect
self.__connecting[1] = true -- lock
conn = socketcore.open(self.__host, self.__port)
-- wake all wait coroutines
for i=2, #self.__connecting do
local co = self.__connecting[i]
self.__connecting[i] = nil
skynet.wakeup(co)
end
self.__connecting[1] = nil -- unlock
return assert(conn)
end
- 对于非关键或接受单次请求无效,支持重入的流程,如定时存盘:
function user:save(query, document)
return mongodb.update(query, document)
end
数据以全量覆盖的形式存盘,那么单次存盘无效认为是可以接受的,下一次请求到来的时候数据能够正确写入;
方案:临界区加锁,无效并发的存盘请求;
function user:safe_save(query, document)
if user.__saving then
-- saving in other coroutine, return succ
return true
end
user.__saving = true -- lock
-- do save
mongodb.update(query, document)
user.__saving = nil -- unlock
return true
end
做得更好的方案,对并发的coroutine做消息降级,兼顾请求有效同时确保请求能被正确唤醒;
function user:safe_save2(query, document)
if user.__saving then
-- saving in other coroutine, sleep
skynet.sleep(delay)
if user.__saving then -- double check
return true
end
end
user.__saving = true -- lock
-- do save
mongodb.update(query, document)
user.__saving = nil -- unlock
return true
end
标签:.__,return,框架,--,self,并发,user,skynet,end
From: https://www.cnblogs.com/linxx-/p/18189905