关于Lua中的协程其实,自己在实际的开发中用的不多,主要是因为Lua作为脚本,其实使用的目的还是为了能够处理一些简单的逻辑,而去给宿主语言一个结果。
但是Lua中的协程还是有需要了解一下的。
协程其实是在很多的语言中都存在的一个概念,而且很多文章开头都是先摆概念:
协程拥有独立的栈,能够和其他的协程共享全局变量,而且开销也很小。开销很小的原因主要还是因为协程有自己的上下文,然后切换协程的时候,只需要将上下文切换就可以了,不需要再去开辟其他的资源,就会很快。
然后主要还是协程的使用方法。
协程的创建有两种方法:
coroutine.create()
coroutine.wrap()
两种方式都可以创建一个协程,在这里其实也就是创建一个函数,使用协程创建的函数,在被调用的时候就会自动的在协程里面运行。
但是两种方式我比较推崇create的方式,因为两种方式创建的协程,启动的方法是不一样的。
-- 使用coroutine.create创建协程,返回一个函数
add_create = coroutine.create(
function (arg1, arg2)
print("create")
print(arg1 .." + ".. arg2.." = "..arg1 + arg2)
--return arg1 + arg2
end
)
-- 执行通过create函数创建的协程,参数就是函数名字以及函数需要的参数
coroutine.resume(add_create,1,2)
-- 上面create创建的函数,需要使用resume进行启动
-- 使用wrap创建函数可以 可以直接启动
add_wrap = coroutine.wrap(
function (arg1, arg2)
print("wrap")
print(arg1 .." + ".. arg2.." = "..arg1 + arg2)
end
)
add_wrap(1,2)
为什么我会推荐create方式去进行创建协程的吗?因为wrap创建的协程,直接使用函数名就可以进行调用,别人在阅读你的代码的时候,就不会一眼看到这是协同程序返回的函数,很容易造成误解,但是使用create进行创建的函数,就需要resume进行唤醒,别人在阅读你的代码的时候,一眼就能看到,这是一个协同程序的返回值。
恢复运行其实和启动运行使用的接口是一样的都是:resum,但是暂停协程使用的是yield接口,
调用yield之后,协程就会停止,直到使用resume进行唤醒
MyPrint = coroutine.create(
function (arg1, arg2, arg3)
print("arg1, arg2 sum is :"..arg1 + arg2)
coroutine.yield()
print("arg1, arg2 mul is :"..arg1 - arg2)
end
)
print("开始")
coroutine.resume(MyPrint,10,6)
print("是否执行完成?")
--coroutine.resume(MyPrint,10,6)
coroutine.resume(MyPrint)
上面的程序中,我在协程函数的中间执行了一下暂停yield函数然后你就会发现,参数1和参数2相减的日志就不会输出了,直到我调用了resume,打印的日志才会继续输出
我注释的部分,其实是我自己在实验一下,就是在我使用resume进行恢复协程的时候,参数是否还需要传递。结果证明,恢复已经暂停的协程的时候,可以不用传递参数。
既然说到了参数,下面我们就要说一下协程的返回值:
协程可以通过两个地方进行返回值的返回,
一个是在协程执行结束的地方,使用return 进行返回,返回的第一个返回值是协程是否被成功启动,第二个返回值是你自己使用return返回的返回值
一个是在被暂停的时候,在yield函数的参数里面,写上自己需要的返回值。
-- 直接使用最后一步的返回值作为协程的返回值
MyPrint = coroutine.create(
function (arg1, arg2, arg3)
return arg1 + arg2
end
)
res5, res6 = coroutine.resume(MyPrint,10,6)
print(res5)
print(res6)
输出结果:
此时第一个返回值代表,协程运行成功,第二个返回值代表自己写的返回值
-- 在协程的运行中间使用yield的参数进行返回
MyPrint = coroutine.create(
function (arg1, arg2, arg3)
coroutine.yield(arg1-arg2)
return arg1 + arg2
end
)
res5, res6 = coroutine.resume(MyPrint,10,6)
-- 因为协程被暂停,所以第一个返回值是resume的启动结果, 第二个返回值:yield的参数
print(res5)
print(res6)
输出结果:
获取协程的状态,我们使用的接口就是:status(),里面的参数就是协程创建之后,返回的函数名
首先我们获取协程的状态其实就是有时候,我们需要判断当前的协程状态,来做不一样的反应。
协程的状态就只三种:running(正在运行)、suspended(暂停)、dead(结束)三种状态。
获取的方式如下:
MyPrint = coroutine.create(
function (arg1, arg2, arg3)
print("coroutine is Running")
print("Coroutine Myprint's status is :"..coroutine.status(MyPrint))
coroutine.yield()
return arg1 + arg2
end
)
coroutine.resume(MyPrint,10,6)
print("Coroutine Myprint's status is :"..coroutine.status(MyPrint))
coroutine.resume(MyPrint)
print("Coroutine Myprint's status is :"..coroutine.status(MyPrint))
输出:
这个接口,我没有Get到意思,可能使用的比较少,但是我单独拎出来的原因是因为,好多博客在写这个接口的时候,含糊其辞,只打印了一个返回值,但其实当你自己运行的时候,其实是两个返回值。
但是没有博客写这个返回值是什么意思,我就去文档查了一下。
接口:running,含义就是返回当前正在运行的协程ID
MyPrint = coroutine.create(
function (arg1, arg2, arg3)
print("coroutine is Running")
print(coroutine.running())
coroutine.yield()
return arg1 + arg2
end
)
coroutine.resume(MyPrint,10,6)
coroutine.resume(MyPrint)
print(coroutine.running())
输出:
大家可以看到,除了返回了协程ID,后边还有一个布尔值,这个布尔值代表了当前是不是主线程,如果是主线程,则为true,
如果不是主线程,是程序自己开启协程。则返回false。
有的博客直接值摆出了第一个输出,没有后面的输出,不知道是因为什么,可能是打印了中间值?才使得后面的布尔变量被抹掉了?还是查一下文档写的清楚一些。