《Lua程序设计[第二版]》第9,10章笔记

第9章 协同程序(coroutine)

协同程序与线程(thread)差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针,同时又与其他协同程序共享全局变量和其他大部分东西。主要区别:一个具有多个线程的程序可以同时运行多个线程,而协同程序却需要彼此协作地运行。就是说一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显示的地要求挂起(suspend)时,它的执行才会暂停。

 

9.1 协同程序基础

Lua将所有关于协同程序的函数放置在一个名为“coroutine”的table中。函数create用于创建新的协同程序,它只有一个参数,就是一个函数。该函数的代码就是协同程序所需执行的内容。

co = coroutine.create(function() print(“hi”) end)

print (co)  –>thread: 003BFE98

协同程序的4种不同的状态:挂起(suspended)、运行(running)、死亡(dead)、和正常(normal)。当创建一个协同程序时,它处于挂起状态。可以通过函数status来检查协同程序的状态:

print(coroutine.status(co))    –>suspended

函数coroutine.resume用于启动或再次启动一个协同程序的执行,并将其状态由挂起状态改为运行:

coroutine.resume(co)            –>hi

函数yield可以让一个运行中的协同程序挂起,而之后可以再次恢复它的运行。

co = coroutine.create( function()

for i=1, 10 do

print(“co  “, i)

coroutine.yield()

end

end)

 

coroutine.resume(co)            –> co  1

print(coroutine.status(co))    –> suspended

coroutine.resume(co)            –> co  2

Lua的协同程序还具有一项有用的机制,就是可以通过一对resume-yield来交换数据。在第一次调用resume时,并没有对应的yield在等待它,因此所有传递给resume的额外参数都将视为协同程序主函数的参数:

co = coroutine.create( function(a, b, c)

print(“co”, a, b, c)

end)

 

coroutine.resume(co, 1, 2, 3)   – coroutine.resume(co)  1,2,3为参数

Lua提供的一种“非对称的协同程序(asymmetric coroutine)”。也就是说,Lua提供了两个函数来控制协同程序的执行,一个用于挂起,另一个用于恢复执行。

 

9.2 管道(pipe)与过滤器(filter)

过滤器(filter)是一种位于生产者和消费者之间的处理功能,可用于对数据的一些交换。过滤器既是一个消费者又是生产者,它唤醒一个生产者促使其产生新值,然后又将变换后的值传递给消费者。

 

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()))

9.3 以协同程序实现迭代器

 

function permgen (a, n)
	n = n or #a		-- 默认n为a的大小
	if n <= 1 then	-- 还需要改变吗?
		printResult(a)
	else
		for i=1, n do 	-- 将第i个元素放到数组末尾
			a[n], a[i] = a[i], a[n]
			permgen(a, n - 1)	-- 生成其余元素的排列
			a[n], a[i] = a[i], a[n]		-- 恢复第i个元素
		end
	end
end

function printResult(a)
	for i = 1, #a do
		io.write(a[i], " ")
	end
	io.write("\n")
end

permgen({1,2,3,4})

将上面的printResult改为yield:

 

function premgen(a, n)
	n = n or #a
	if n <= 1 then
		coroutine.yield(a)
	else
		for i=1, n do 	-- 将第i个元素放到数组末尾
			a[n], a[i] = a[i], a[n]
			permgen(a, n - 1)	-- 生成其余元素的排列
			a[n], a[i] = a[i], a[n]		-- 恢复第i个元素
		end
	end
end

function permutations(a)
	local co = coroutine.create( function () permgen(a) end)
	return function()	-- 迭代器
		local code, res = coroutine.resume(co)
		return res
	end
end

function printResult(d)
	for i = 1, #d do
		io.write(d[i], " ")
	end
	io.write("\n")
end

for p in permutations {"a", "b", "c"} do
	printResult(p)
end

9.4 非抢占式的多线程

协同程序是非抢占式的。当一个协同程序运行时,是无法从外部停止它的。只有当协同程序显示地要求挂起时(调用yield),它才会停止。

 

第10章 完整的示例

10.1 数据描述

略。

 

10.2 马尔可夫链算法

略.

 

第11章 … 请看该系列的下一篇


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值