skynet:fork

skynet 是多线程框架,此外在 skynet 中,每个服务对应一个 lua 虚拟机,一个虚拟机上可以跑多个协程,但同一时刻只能有一个协程,每条消息处理由协程来完成。

在 skynet 中,线程创建方式:

skynet.fork(func,…)

一、测试

main.lua

local skynet = require "skynet"

skynet.start(function()
        
        function myfork( val )
                while true do
                        print('myfork ', val, ' !!!! ')
                        skynet.sleep(200)
                end
        end
 
        local co1 = skynet.fork(myfork, 1)
        local co2 = skynet.fork(myfork, 2)
 
end)

测试结果:
> /root/skynet-master/skynet ./config/config
可以看到两个线程函数交替运行。

二、skynet.fork 原理

skynet.lua

function skynet.fork(func,...)
	local n = select("#", ...)--获取参数个数
	local co
	if n == 0 then
		co = co_create(func)
	else
		local args = { ... }	
		--table.unpack(table, start, end):返回 table 中 [start, end] 区间的元素,start 默认为1,end 默认为最后一个元素的位置		
		co = co_create(function() func(table.unpack(args,1,n)) end)--创建一个协程,相当于创建一个lua虚拟机
	end
	tinsert(fork_queue, co)--将协程加到fork_queue队列中 
	return co
end

从协程池中取出一个空闲协程,没有,则创建一个新的协程:

local function co_create(f)
	local co = tremove(coroutine_pool) --从协程池table末尾取出一个协程
	
	--协程池table为空,则创建新协程
	if co == nil then
		co = coroutine_create(function(...)
			f(...)
			while true do
				local session = session_coroutine_id[co]
				if session and session ~= 0 then
					local source = debug.getinfo(f,"S")
					skynet.error(string.format("Maybe forgot response session %s from %s : %s:%d",
						session,
						skynet.address(session_coroutine_address[co]),
						source.source, source.linedefined))
				end
				-- coroutine exit
				local tag = session_coroutine_tracetag[co]
				if tag ~= nil then
					if tag then c.trace(tag, "end")	end
					session_coroutine_tracetag[co] = nil
				end
				local address = session_coroutine_address[co]
				if address then
					session_coroutine_id[co] = nil
					session_coroutine_address[co] = nil
				end

				-- recycle co into pool
				f = nil
				coroutine_pool[#coroutine_pool+1] = co--把新协程加入协程池
				-- recv new main function f
				f = coroutine_yield "SUSPEND"
				f(coroutine_yield())
			end
		end)
	else
		-- pass the main function f to coroutine, and restore running thread
		local running = running_thread
		coroutine_resume(co, f)
		running_thread = running
	end
	return co
end

处理fork_queue中的fork协程

function skynet.dispatch_message(...)
	local succ, err = pcall(raw_dispatch_message,...)
	
	--处理fork_queue中的fork协程
	while true do
		local co = tremove(fork_queue,1)
		if co == nil then
			break
		end
		local fork_succ, fork_err = pcall(suspend,co,coroutine_resume(co))
		if not fork_succ then
			if succ then
				succ = false
				err = tostring(fork_err)
			else
				err = tostring(err) .. "\n" .. tostring(fork_err)
			end
		end
	end
	assert(succ, tostring(err))
end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值