线程和协同程序区别

线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。

在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。

协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。

方法

描述

coroutine.create()

创建 coroutine,返回 coroutine, 参数是一个函数,创建后的协同程序状态为suspended挂起状态(另,running运行状态,dead死亡状态),并没有运行,当和 resume 配合使用的时候就唤醒函数调用

coroutine.resume()

重启 coroutine,传入第一个参数是create函数返回的协程,剩下的额外参数是传递给协程运行的参数,下次使用resume唤醒协程时,会从之前暂停的点继续执行,resume会把自己额外的参数(即除了协程的句柄的其他参数)传递给yield语句(可理解为用resume的额外参数直接替换yield语句)。返回值分两种情况:resume成功的情况下返回true以及上一次 yield函数传入的参数;失败情况下返回false,以及错误信息。第一次执行resume操作时,会从create传入的函数开始执行,之后会在该协程主函数调用yield的下一个操作开始执行,直到整个函数执行完毕。

coroutine.yield()

让一个运行中的协程挂起自己,然后通过resume函数让其恢复运行。调用yield操作,必须在协程中。

coroutine.status()

查看 coroutine 的状态

注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序

coroutine.wrap()

创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine。wrap函数相当于结合了create和resume函数,所不同的是,wrap函数返回的是创建好的协程,下一次直接传入参数调用该协程即可,无需调用resume函数。

coroutine.running()

返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号

1.看一个官网例子稍微修改后的例子:

function foo (a)
    print("foo", a)
    coroutine.yield(2*a)
    return 10 --不会执行
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))

以上实例结果如下:

lua 并发运行 lua多线程实例_协同程序

step1:执行第一个print,出现resume,切换进入create的协程function中,打印出  co-body 1 10

step2:执行function中第二句(定义一个局部变量r并赋值),进入foo,打印出 foo  2

step3:执行foo中的第二句,return时遇到yield(foo中的这个return 10并没有得到执行,因为要先执行yield再return),协程正常暂停,此时resume函数立刻return一个true和 coroutine.yield(2*a)的参数 2*a(=4)
step4:执行print,打印出main   true   4

2.来看第二波print:

function foo (a)
    print("foo", a)
    coroutine.yield(2*a)
    return 10 
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))
 print("main", coroutine.resume(co, "r"))

实例结果如下:

lua 并发运行 lua多线程实例_协程_02

 (接上面的step)
step5:执行第二个print,程序从上次暂停的为止foo(a)中的return执行,且resume把参数(字符"r")传递给yield,则foo返回值为字符"10",赋值给local r ,则打印出 co-body  10

step6:执行 local r, s = coroutine.yield(a+b, a-b),协程正常暂停,此时resume函数立刻return 一个true和coroutine.yield(a+b,a-b)的参数a+b,a-b,a和b分别是最开始开启这一个协程时传入的参数1和10,打印出 main   true  11  -9

3.再看第三个print:

function foo (a)
    print("foo", a)
    coroutine.yield(2*a)
    return 10 
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) -- yield会直接接受来自resume的参数,将额外参数直接返回
       print("co-body", r, s)
       return b, "end"
 end)

 print("main", coroutine.resume(co, 1, 10))
 print("main", coroutine.resume(co, "r"))
 print("main", coroutine.resume(co, "x", "y"))

打印结果如下:

 

lua 并发运行 lua多线程实例_lua_03

  (接上面的step)

step7:执行第三个print时,又遇到resume,从上次暂停的地方运行,resume把参数x,y传递给yield,则local r,s = x ,y,打印出 co-body  x  y

step8:因为协程是正常执行到return,正常结束,resume返回true和协程中return的值 10  end。则第三个print,则打印出 main  true  10  end

4.最后看一个简单的例子:

function foo ()
	for i=1,10 do
		print(i)
		if(i == 7) then
			coroutine.resume(co)
 		end
 	end
end
     
 co = coroutine.create(function ()
 	print("test")
    coroutine.yield()
    print("end")
 end)

coroutine.resume(co)
foo()

输出结果:

 

lua 并发运行 lua多线程实例_协同程序_04