Lua程序设计(六十七)

哪个协程占据主循环

协程的一个经典问题就是生产者-消费者问题。在生产者-消费者问题中涉及两个函数,一个函数不断地产生值(比如,从一个文件中读取),另一个函数不断地消费这些值(比如,将值写入另一个文件中)。

function producer ()
	while true do
		local x = io.read()
		send(x)
	end
end

function consumer()
	while true do
		local x = receive()
		io.write(x, "\n")
	end
end

我们的问题在于要如何将sendreceive匹配起来,也就是“谁占据主循环”问题的典型实例。其中,生产者和消费者都处于活跃状态,它们各自拥有自己的主循环,并且都将对方视为一个可调用的服务。

由于成对的resume-yield可以颠倒调用者与被调用者之间的关系,因此协程提供了一种无需修改生产者和消费者的代码结构就能匹配它们执行顺序的理想工具。 当一个协程调用yield函数时,它不是进入了一个新的函数,而是返回一个挂起的调用(调用的是函数resume)。同样地,对函数resume的调用也不会启动一个新的函数,而是返回一个对函数yield的调用。这种特性恰好可以用于匹配sendreceive,使得双方都认为自己是主动方而对方是被动方。因此,receive唤醒生产者的执行使其能产生一个新值,然后send则让出执行权,将生成的值传递给消费者:

function receive ()
	local status, value = coroutine.resume(producer)
	return value
end

function send (x)
	coroutine.yield(x)
end

在这种设计中,程序通过调用消费者启动。每当消费者需要新值时就调用唤醒生产者,生产者向消费者返回新值后挂起,直到消费者再次将其唤醒。因此,我们将这种设计成为消费者驱动(consumer-driven)式的设计。另一个方式则是使用生产者驱动的设计。虽然两种设计思路看上去截然相反,但实际上它们的整体思想相同。

我们可以通过过滤器来扩展上述设计。过滤器位于生产者和消费者之间,用于完成一些对数据进行某种变换的任务。过滤器即是一个消费者又是一个生产者,它通过唤醒一个生产者来获得新值,然后又将变换后的值传递给消费者。

function receive (prod)
	local status, value = coroutine.resume(prod)
	return value
end

function send (x)
	coroutine.yield(x)
end

function producer ()
	return coroutine.create(function ()
		while true do
			local x = io.read()
			send(x)
		end
	end)
end

function filter (prod)
	return coroutine.create(function ()
		for line = 1,math.huge do
			local x = receive(prod)
			x = string.format('%5d %s", line, x)
			send(x)
		end
	end)
end

function consumer (prod)
	while true do
		local x = receive(prod)
		io.write(x,"\n")
	end
end

consumer(filter(producer))
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值