skynet答疑一 --skynet.start参数为什么要在定时器中执行

有人在群里问到为什么skynet.start函数的参数为要在一个定时器中执行,不能直接执行吗?skynet.start函数如下:

function skynet.start(start_func)
    c.callback(skynet.dispatch_message)
    skynet.timeout(0, function()
        skynet.init_service(start_func)
    end)
end

有人认为这是为了一个服务尽快返回。他们认为启动一个新的服务时,由于这个操作是阻塞的,要尽快让这个操作返回,因为b服务的文件里可能有耗时的计算。

其实这个观点是错误的,a在启动另一个服务b,还没有到加载b服务的文件时,其实b服务就已经返回了,产生了一个服务地址,此时a服务就可以向b服务发送消息了。加载b服务的文件其实也有消息驱动的,下面是一个服务启动另一个服务时的简要时序图:

 

image.png

 

原因之一是在skynet.timeout中有一个创建协程的操作,要保证所有函数执行的都是在协程里进行的。为什么呢?要找到问题的原因,一定要看看源码的实现,skynet.timeou的实现如下:

function skynet.timeout(ti, func)
    local session = c.intcommand("TIMEOUT",ti)
    assert(session)
    local co = co_create(func)
    assert(session_id_coroutine[session] == nil)
    session_id_coroutine[session] = co
end

在c底层skynet.timeout会发送一个定时为0的定时器消息,然后在创建一个协程。我们来探讨一下为什么要有这两步。

首先一些阻塞的调用如skynet.call是利用协程实现的,如果skynet.start的执行函数不在协程里执行,那么调用skynet.call将会报错--attempt to yield from outside a coroutine。由于调用skynet.call的语义就是将当前执行的函数挂起,这样一来就只能利用协程来实现了,因为你是不能把协程之外的函数挂起的。如果阻塞call都没有实现,那一定不是好的实现。

还有就是skynet.fork的实现。如果skynet.start主函数不在协程里执行,那么skynet.fork将无处施展。

说了为什么要创建协程,我还是没有讲清楚为什么要开启一个定时器消息。我思来想去,我的理由是为了方便统一处理,既然后续的逻辑执行都是一个个消息回调函数的处理,而且一开始主函数就要处理协程的问题,那么干脆这个主函数也用回调消息的方式来执行。

 

 

欢迎加入QQ群 858791125 讨论skynet,游戏后台开发,lua脚本语言等问题。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值