初试定时器

新入门skynet系列视频b站网址 https://www.bilibili.com/video/BV19d4y1678X

skynet里面提供了定时器。

skynet.timeout 实际上是请求定时器线程 往自己的队列添加一个消息。首先会向系统注册一个定时器,然后获取一个协程。当定时器触发时,通过定时器的session找到对应的协程,并执行这个协程。

function skynet.timeout(ti, func)
	local session = c.intcommand("TIMEOUT",ti) --seesion是通过当前服务分配的
	assert(session)
	local co = co_create_for_timeout(func, ti) -- 获取一个协程 注意设置了任务函数
	assert(session_id_coroutine[session] == nil)
	session_id_coroutine[session] = co --建立session 和 协程的 对应关系
	return co	-- for debug
end

上面行2 转到下面的c代码

static const char *
cmd_timeout(struct skynet_context * context, const char * param) {
	char * session_ptr = NULL;
	int ti = strtol(param, &session_ptr, 10);
	int session = skynet_context_newsession(context);//获取一个服务内唯一的 session
	skynet_timeout(context->handle, ti, session);//去注册一个定时器 
	sprintf(context->result, "%d", session);
	return context->result;
}

当定时器触发时,会向当前服务所在的队列push一个响应消息。我们看处理这个消息的过程。当然lua层的处理函数入口是 skynet.dispatch_message

function skynet.dispatch_message(...)
	local succ, err = pcall(raw_dispatch_message,...)-- next
	while true do
		if fork_queue.h > fork_queue.t then
			-- queue is empty
			fork_queue.h = 1  --head
			fork_queue.t = 0  --tail
			break
		end
		-- pop queue
		local h = fork_queue.h
		local co = fork_queue[h]
		fork_queue[h] = nil
		fork_queue.h = h + 1

		local fork_succ, fork_err = pcall(suspend,co,coroutine_resume(co))
		
	end
	assert(succ, tostring(err))
end

我们看 第2行代码的 raw_dispatch_message函数

local function raw_dispatch_message(prototype, msg, sz, session, source)
	-- skynet.PTYPE_RESPONSE = 1, read skynet.h
	if prototype == 1 then --这里是处理响应
		local co = session_id_coroutine[session] --响应消息的处理都是 通过seesion去得到协程 然后执行协程;因为session是本服务分配的 所以具有唯一性
        session_id_coroutine[session] = nil
        suspend(co, coroutine_resume(co, true, msg, sz, session))
		
	else --这里主要是处理lua text socket 等消息类型
		--略
	end
end

通过第4行我们找到协程。第6行唤醒协程开始执行 任务函数。

关于定时器的内部实现详细分析,会在 定时器底层实现 里面讲到

posted @ 2022-12-08 15:24  程序员阿钢  阅读(148)  评论(0编辑  收藏  举报