leevis.com icon indicating copy to clipboard operation
leevis.com copied to clipboard

lua的协程生产者消费者

Open vislee opened this issue 8 years ago • 0 comments

Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。然而,lua的协程和多线程系统中的线程不同,协程只在显式的调用了yield函数时才会挂起。同一时间也只有一个协程在运行。

  • 协程函数:
    • coroutine.create(f): 接受一个函数,该函数是协程的主函数,返回一个thread的对象。
    • coroutine.resume (co [, val1, ···]):接受一个thread的对象(coroutine.create的返回)和多个变量。首次运行时,变量被赋予coroutine.create的参数f这个函数,作为入参。如果上次是从coroutine.yield返回的,再次被调度是从coroutine.yield赋值开始执行,因此入参是被赋值到coroutine.yield的赋值开始运行。
    • coroutine.yield(...) :接受多个参数,把参数从协程返回并挂起协程。再此调用coroutine.resume时,会把该函数的参数赋值到接受coroutine.yield的变量,并从挂起处继续执行。

看云风写的这个例子就明白多了:

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end

     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)

     print("main", coroutine.resume(co, 1, 10))
     --[[ 运行结果:
co-body	1	10
foo	2
main	true	4
     ]]
     print("main", coroutine.status(co))
    --[[
main	suspended
    ]]
     print("main", coroutine.resume(co, "rrr"))
     --[[
co-body	rrr
main	true	11	-9
     ]]
     print("main", coroutine.resume(co, "x", "y"))
     --[[
co-body	x	y
main	true	10	end
     ]]

     print("main", coroutine.resume(co, "xx", "xy"))
     --[[
main	false	cannot resume dead coroutine
     ]]

总结:coroutine.resume的返回是coroutine.yield的参数。 coroutine.yield的返回是coroutine.resume的参数。

当调用coroutine.resume时,它会将传入的参数作为当前协程coroutine.yield的返回值,然后恢复该被挂起的协程,使其继续执行。当调用coroutine.yield时,它会将传入的参数作为当前协程的返回值,然后挂起当前协程。

lua的协程,生产者消费者

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

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

function product()
	return coroutine.create(function() 
		while true do
			local x = io.read()
			if x == "" then break end
			send(x)
		end
	end)
end

function consumer(prod)
	while true do
		local x = receive(prod)
		if not x then
			print("status:", coroutine.status(prod))
			break
		end
		print('==>',x)
	end
end


consumer(product())

以下是chatgpt的讲解:

Lua协程是一种特殊的线程,它允许在同一个Lua虚拟机中创建多个协程,并在它们之间进行协作式的多任务处理。Lua协程的特点是可以暂停当前协程的执行,切换到另一个协程继续执行,之后再回到原来的协程继续执行。这种切换是由Lua虚拟机控制的,协程本身并没有多线程的并发性,但通过协作式的方式可以实现高效的多任务处理。

Lua协程的实现依赖于Lua的协程库。协程库中提供了一些API来创建协程、启动协程、挂起协程、唤醒协程等操作。其中最常用的API是coroutine.create、coroutine.resume、coroutine.yield和coroutine.status。

举个例子,下面是一个简单的Lua协程示例,它使用协程实现了一个计数器:


function counter()
    local count = 0
    while true do
        count = count + 1
        print("count=", count)
        coroutine.yield()
    end
end

co = coroutine.create(counter)

while true do
    coroutine.resume(co)
    -- 每次执行时暂停1秒钟
    os.execute("sleep 1")
end

这个示例中,我们定义了一个counter函数,它用来计数并打印计数器的值。在函数内部,我们使用了一个无限循环来不断执行计数操作,并通过coroutine.yield()函数暂停协程的执行,等待下一次执行。

在主程序中,我们首先使用coroutine.create函数创建了一个协程,然后在一个无限循环中使用coroutine.resume函数来启动协程,并使用os.execute("sleep 1")函数暂停1秒钟。由于coroutine.resume函数会在每次执行时唤醒协程,并从上次暂停的位置继续执行,所以计数器的值会不断增加。

需要注意的是,Lua协程的使用需要注意协程间的切换和同步问题,否则容易出现死锁或者无法预期的结果。因此,在使用Lua协程时需要仔细考虑各种情况,并严格控制协程之间的同步和通信。

vislee avatar Mar 10 '17 10:03 vislee